diff --git a/akka-actor-tests/src/test/java/akka/util/JavaDuration.java b/akka-actor-tests/src/test/java/akka/util/JavaDuration.java new file mode 100644 index 0000000000..1cea685880 --- /dev/null +++ b/akka-actor-tests/src/test/java/akka/util/JavaDuration.java @@ -0,0 +1,16 @@ +package akka.util; + +import org.junit.Test; + +public class JavaDuration { + + @Test void testCreation() { + final Duration fivesec = Duration.create(5, "seconds"); + final Duration threemillis = Duration.parse("3 millis"); + final Duration diff = fivesec.minus(threemillis); + assert diff.lt(fivesec); + assert Duration.Zero().lteq(Duration.Inf()); + assert Duration.Inf().gt(Duration.Zero().neg()); + } + +} diff --git a/akka-actor-tests/src/test/scala/akka/actor/actor/Bench.scala b/akka-actor-tests/src/test/scala/akka/actor/actor/Bench.scala index f018de635c..1f121babd5 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/actor/Bench.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/actor/Bench.scala @@ -78,7 +78,7 @@ object Chameneos { var sumMeetings = 0 var numFaded = 0 - override def preStart = { + override def preStart() = { for (i <- 0 until numChameneos) actorOf(new Chameneo(self, colours(i % 3), i)) } diff --git a/akka-actor-tests/src/test/scala/akka/actor/supervisor/RestartStrategySpec.scala b/akka-actor-tests/src/test/scala/akka/actor/supervisor/RestartStrategySpec.scala index f2a3103d08..c2af94ba1a 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/supervisor/RestartStrategySpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/supervisor/RestartStrategySpec.scala @@ -46,7 +46,7 @@ class RestartStrategySpec extends JUnitSuite { secondRestartLatch.open } - override def postStop = { + override def postStop() = { stopLatch.open } }) @@ -131,7 +131,7 @@ class RestartStrategySpec extends JUnitSuite { thirdRestartLatch.open } - override def postStop = { + override def postStop() = { if (restartLatch.isOpen) { secondRestartLatch.open } @@ -189,7 +189,7 @@ class RestartStrategySpec extends JUnitSuite { secondRestartLatch.open } - override def postStop = { + override def postStop() = { stopLatch.open } }) @@ -243,7 +243,7 @@ class RestartStrategySpec extends JUnitSuite { restartLatch.open } - override def postStop = { + override def postStop() = { stopLatch.open } }) diff --git a/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorSpec.scala index 253570f576..668a2709cc 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/supervisor/SupervisorSpec.scala @@ -381,7 +381,7 @@ class SupervisorSpec extends WordSpec with MustMatchers with BeforeAndAfterEach inits.get must be (3) - supervisor.shutdown + supervisor.shutdown() } } } diff --git a/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala b/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala index 206d06d1c4..b61bd1a937 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/supervisor/Ticket669Spec.scala @@ -14,7 +14,7 @@ import org.scalatest.matchers.MustMatchers class Ticket669Spec extends WordSpec with MustMatchers with BeforeAndAfterAll { import Ticket669Spec._ - override def afterAll = Actor.registry.shutdownAll() + override def afterAll() { Actor.registry.shutdownAll() } "A supervised actor with lifecycle PERMANENT" should { "be able to reply on failure during preRestart" in { @@ -65,7 +65,7 @@ object Ticket669Spec { self.reply_?("failure1") } - override def postStop { + override def postStop() { self.reply_?("failure2") } } diff --git a/akka-actor-tests/src/test/scala/akka/dataflow/DataFlowSpec.scala b/akka-actor-tests/src/test/scala/akka/dataflow/DataFlowSpec.scala index e0e0a09e6b..412605c02b 100644 --- a/akka-actor-tests/src/test/scala/akka/dataflow/DataFlowSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dataflow/DataFlowSpec.scala @@ -36,7 +36,7 @@ class DataFlowTest extends Spec with ShouldMatchers with BeforeAndAfterAll { latch.await(10,TimeUnit.SECONDS) should equal (true) result.get should equal (42) - List(x,y,z).foreach(_.shutdown) + List(x,y,z).foreach(_.shutdown()) } it("should be able to sum a sequence of ints") { @@ -67,7 +67,7 @@ class DataFlowTest extends Spec with ShouldMatchers with BeforeAndAfterAll { latch.await(10,TimeUnit.SECONDS) should equal (true) result.get should equal (sum(0,ints(0,1000))) - List(x,y,z).foreach(_.shutdown) + List(x,y,z).foreach(_.shutdown()) } /* it("should be able to join streams") { @@ -158,7 +158,7 @@ class DataFlowTest extends Spec with ShouldMatchers with BeforeAndAfterAll { val setV = thread { v << y } - List(x,y,z,v) foreach (_.shutdown) + List(x,y,z,v) foreach (_.shutdown()) latch.await(2,TimeUnit.SECONDS) should equal (true) }*/ } diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/ActorModelSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/ActorModelSpec.scala index 4e60ffcc96..d5cea19bf5 100644 --- a/akka-actor-tests/src/test/scala/akka/dispatch/ActorModelSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dispatch/ActorModelSpec.scala @@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicLong import java.util.concurrent. {ConcurrentHashMap, CountDownLatch, TimeUnit} import akka.actor.dispatch.ActorModelSpec.MessageDispatcherInterceptor import akka.util.{Duration, Switch} +import org.multiverse.api.latches.StandardLatch object ActorModelSpec { @@ -110,13 +111,13 @@ object ActorModelSpec { super.dispatch(invocation) } - private[akka] abstract override def start { - super.start + private[akka] abstract override def start() { + super.start() starts.incrementAndGet() } - private[akka] abstract override def shutdown { - super.shutdown + private[akka] abstract override def shutdown() { + super.shutdown() stops.incrementAndGet() } } @@ -216,6 +217,21 @@ abstract class ActorModelSpec extends JUnitSuite { msgsProcessed = 0, restarts = 0 ) + + val futures = for(i <- 1 to 10) yield Future { i } + await(dispatcher.stops.get == 2)(withinMs = dispatcher.timeoutMs * 5) + assertDispatcher(dispatcher)(starts = 2, stops = 2) + + val a2 = newTestActor + a2.start + val futures2 = for(i <- 1 to 10) yield Future { i } + + await(dispatcher.starts.get == 3)(withinMs = dispatcher.timeoutMs * 5) + assertDispatcher(dispatcher)(starts = 3, stops = 2) + + a2.stop + await(dispatcher.stops.get == 3)(withinMs = dispatcher.timeoutMs * 5) + assertDispatcher(dispatcher)(starts = 3, stops = 3) } @Test def dispatcherShouldProcessMessagesOneAtATime { diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/ExecutorBasedEventDrivenDispatcherActorsSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/ExecutorBasedEventDrivenDispatcherActorsSpec.scala index dfdaf9794d..a97238bf7e 100644 --- a/akka-actor-tests/src/test/scala/akka/dispatch/ExecutorBasedEventDrivenDispatcherActorsSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dispatch/ExecutorBasedEventDrivenDispatcherActorsSpec.scala @@ -8,7 +8,7 @@ import akka.actor.Actor import Actor._ /** - * Tests the behaviour of the executor based event driven dispatcher when multiple actors are being dispatched on it. + * Tests the behavior of the executor based event driven dispatcher when multiple actors are being dispatched on it. * * @author Jan Van Besien */ diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala index a26ee498a0..b74526118e 100644 --- a/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala @@ -260,8 +260,9 @@ class FutureSpec extends JUnitSuite { def receive = { case (add: Int, wait: Int) => Thread.sleep(wait); self reply_? add } }).start() } - def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!) } - assert(Futures.fold(0)(futures)(_ + _).awaitBlocking.result.get === 45) + val timeout = 10000 + def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!, timeout) } + assert(Futures.fold(0, timeout)(futures)(_ + _).await.result.get === 45) } @Test def shouldFoldResultsByComposing { @@ -270,8 +271,8 @@ class FutureSpec extends JUnitSuite { def receive = { case (add: Int, wait: Int) => Thread.sleep(wait); self reply_? add } }).start() } - def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!) } - assert(futures.foldLeft(Future(0))((fr, fa) => for (r <- fr; a <- fa) yield (r + a)).awaitBlocking.result.get === 45) + def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!, 10000) } + assert(futures.foldLeft(Future(0))((fr, fa) => for (r <- fr; a <- fa) yield (r + a)).get === 45) } @Test def shouldFoldResultsWithException { @@ -285,12 +286,13 @@ class FutureSpec extends JUnitSuite { } }).start() } - def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!) } - assert(Futures.fold(0)(futures)(_ + _).awaitBlocking.exception.get.getMessage === "shouldFoldResultsWithException: expected") + val timeout = 10000 + def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!, timeout) } + assert(Futures.fold(0, timeout)(futures)(_ + _).await.exception.get.getMessage === "shouldFoldResultsWithException: expected") } @Test def shouldFoldReturnZeroOnEmptyInput { - assert(Futures.fold(0)(List[Future[Int]]())(_ + _).awaitBlocking.result.get === 0) + assert(Futures.fold(0)(List[Future[Int]]())(_ + _).get === 0) } @Test def shouldReduceResults { @@ -299,8 +301,9 @@ class FutureSpec extends JUnitSuite { def receive = { case (add: Int, wait: Int) => Thread.sleep(wait); self reply_? add } }).start() } - def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!) } - assert(Futures.reduce(futures)(_ + _).awaitBlocking.result.get === 45) + val timeout = 10000 + def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!, timeout) } + assert(Futures.reduce(futures, timeout)(_ + _).get === 45) } @Test def shouldReduceResultsWithException { @@ -314,34 +317,15 @@ class FutureSpec extends JUnitSuite { } }).start() } - def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!) } - assert(Futures.reduce(futures)(_ + _).awaitBlocking.exception.get.getMessage === "shouldFoldResultsWithException: expected") + val timeout = 10000 + def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!, timeout) } + assert(Futures.reduce(futures, timeout)(_ + _).await.exception.get.getMessage === "shouldFoldResultsWithException: expected") } @Test(expected = classOf[UnsupportedOperationException]) def shouldReduceThrowIAEOnEmptyInput { Futures.reduce(List[Future[Int]]())(_ + _).await.resultOrException } - @Test def resultWithinShouldNotThrowExceptions { - val latch = new StandardLatch - - val actors = (1 to 10).toList map { _ => - actorOf(new Actor { - def receive = { case (add: Int, wait: Boolean, latch: StandardLatch) => if (wait) latch.await; self reply_? add } - }).start() - } - - def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) => actor.!!) } - val result = for(f <- futures) yield f.valueWithin(2, TimeUnit.SECONDS) - latch.open - val done = result collect { case Some(Right(x)) => x } - val undone = result collect { case None => None } - val errors = result collect { case Some(Left(t)) => t } - assert(done.size === 5) - assert(undone.size === 5) - assert(errors.size === 0) - } - @Test def receiveShouldExecuteOnComplete { val latch = new StandardLatch val actor = actorOf[TestActor].start() @@ -389,7 +373,7 @@ class FutureSpec extends JUnitSuite { assert(f3.resultOrException === Some("SUCCESS")) // make sure all futures are completed in dispatcher - assert(Dispatchers.defaultGlobalDispatcher.futureQueueSize === 0) + assert(Dispatchers.defaultGlobalDispatcher.pendingFutures === 0) } @Test def shouldBlockUntilResult { @@ -498,6 +482,24 @@ class FutureSpec extends JUnitSuite { assert(a.get === 5) assert(b.get === 3) assert(result2.get === 50) + Thread.sleep(100) + + // make sure all futures are completed in dispatcher + assert(Dispatchers.defaultGlobalDispatcher.pendingFutures === 0) + } + + @Test def shouldNotAddOrRunCallbacksAfterFailureToBeCompletedBeforeExpiry { + val latch = new StandardLatch + val f = new DefaultCompletableFuture[Int](0) + Thread.sleep(25) + f.onComplete( _ => latch.open ) //Shouldn't throw any exception here + + assert(f.isExpired) //Should be expired + + f.complete(Right(1)) //Shouldn't complete the Future since it is expired + + assert(f.value.isEmpty) //Shouldn't be completed + assert(!latch.isOpen) //Shouldn't run the listener } @Test def futureDataFlowShouldEmulateBlocking1 { @@ -620,4 +622,14 @@ class FutureSpec extends JUnitSuite { assert(result.get === Some("Hello")) } + + @Test def ticket812FutureDispatchCleanup { + val dispatcher = implicitly[MessageDispatcher] + assert(dispatcher.pendingFutures === 0) + val future = Future({Thread.sleep(100);"Done"}, 10) + intercept[FutureTimeoutException] { future.await } + assert(dispatcher.pendingFutures === 1) + Thread.sleep(100) + assert(dispatcher.pendingFutures === 0) + } } diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/MailboxConfigSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/MailboxConfigSpec.scala index 9ddbfdc332..0da861350d 100644 --- a/akka-actor-tests/src/test/scala/akka/dispatch/MailboxConfigSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dispatch/MailboxConfigSpec.scala @@ -23,8 +23,8 @@ abstract class MailboxSpec extends def factory: MailboxType => MessageQueue name should { - "create a !blockDequeue && unbounded mailbox" in { - val config = UnboundedMailbox(false) + "create an unbounded mailbox" in { + val config = UnboundedMailbox() val q = factory(config) ensureInitialMailboxState(config, q) @@ -37,8 +37,8 @@ abstract class MailboxSpec extends f.await.resultOrException must be === Some(null) } - "create a !blockDequeue and bounded mailbox with 10 capacity and with push timeout" in { - val config = BoundedMailbox(false, 10, Duration(10,TimeUnit.MILLISECONDS)) + "create a bounded mailbox with 10 capacity and with push timeout" in { + val config = BoundedMailbox(10, Duration(10,TimeUnit.MILLISECONDS)) val q = factory(config) ensureInitialMailboxState(config, q) @@ -59,30 +59,16 @@ abstract class MailboxSpec extends } "dequeue what was enqueued properly for unbounded mailboxes" in { - testEnqueueDequeue(UnboundedMailbox(false)) + testEnqueueDequeue(UnboundedMailbox()) } "dequeue what was enqueued properly for bounded mailboxes" in { - testEnqueueDequeue(BoundedMailbox(false, 10000, Duration(-1, TimeUnit.MILLISECONDS))) + testEnqueueDequeue(BoundedMailbox(10000, Duration(-1, TimeUnit.MILLISECONDS))) } "dequeue what was enqueued properly for bounded mailboxes with pushTimeout" in { - testEnqueueDequeue(BoundedMailbox(false, 10000, Duration(100, TimeUnit.MILLISECONDS))) + testEnqueueDequeue(BoundedMailbox(10000, Duration(100, TimeUnit.MILLISECONDS))) } - - /** FIXME Adapt test so it works with the last dequeue - - "dequeue what was enqueued properly for unbounded mailboxes with blockDeque" in { - testEnqueueDequeue(UnboundedMailbox(true)) - } - - "dequeue what was enqueued properly for bounded mailboxes with blockDeque" in { - testEnqueueDequeue(BoundedMailbox(true, 1000, Duration(-1, TimeUnit.MILLISECONDS))) - } - - "dequeue what was enqueued properly for bounded mailboxes with blockDeque and pushTimeout" in { - testEnqueueDequeue(BoundedMailbox(true, 1000, Duration(100, TimeUnit.MILLISECONDS))) - }*/ } //CANDIDATE FOR TESTKIT @@ -111,8 +97,8 @@ abstract class MailboxSpec extends q match { case aQueue: BlockingQueue[_] => config match { - case BoundedMailbox(_,capacity,_) => aQueue.remainingCapacity must be === capacity - case UnboundedMailbox(_) => aQueue.remainingCapacity must be === Int.MaxValue + case BoundedMailbox(capacity,_) => aQueue.remainingCapacity must be === capacity + case UnboundedMailbox() => aQueue.remainingCapacity must be === Int.MaxValue } case _ => } @@ -165,10 +151,8 @@ abstract class MailboxSpec extends class DefaultMailboxSpec extends MailboxSpec { lazy val name = "The default mailbox implementation" def factory = { - case UnboundedMailbox(blockDequeue) => - new DefaultUnboundedMessageQueue(blockDequeue) - case BoundedMailbox(blocking, capacity, pushTimeOut) => - new DefaultBoundedMessageQueue(capacity, pushTimeOut, blocking) + case UnboundedMailbox() => new DefaultUnboundedMessageQueue() + case BoundedMailbox(capacity, pushTimeOut) => new DefaultBoundedMessageQueue(capacity, pushTimeOut) } } @@ -176,9 +160,7 @@ class PriorityMailboxSpec extends MailboxSpec { val comparator = PriorityGenerator(_.##) lazy val name = "The priority mailbox implementation" def factory = { - case UnboundedMailbox(blockDequeue) => - new UnboundedPriorityMessageQueue(blockDequeue, comparator) - case BoundedMailbox(blocking, capacity, pushTimeOut) => - new BoundedPriorityMessageQueue(capacity, pushTimeOut, blocking, comparator) + case UnboundedMailbox() => new UnboundedPriorityMessageQueue(comparator) + case BoundedMailbox(capacity, pushTimeOut) => new BoundedPriorityMessageQueue(capacity, pushTimeOut, comparator) } } \ No newline at end of file diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/PriorityDispatcherSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/PriorityDispatcherSpec.scala index f256715b8c..002267a6c7 100644 --- a/akka-actor-tests/src/test/scala/akka/dispatch/PriorityDispatcherSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/dispatch/PriorityDispatcherSpec.scala @@ -10,11 +10,11 @@ class PriorityDispatcherSpec extends WordSpec with MustMatchers { "A PriorityExecutorBasedEventDrivenDispatcher" must { "Order it's messages according to the specified comparator using an unbounded mailbox" in { - testOrdering(UnboundedMailbox(false)) + testOrdering(UnboundedMailbox()) } "Order it's messages according to the specified comparator using a bounded mailbox" in { - testOrdering(BoundedMailbox(false,1000)) + testOrdering(BoundedMailbox(1000)) } } diff --git a/akka-actor-tests/src/test/scala/akka/testkit/CallingThreadDispatcherModelSpec.scala b/akka-actor-tests/src/test/scala/akka/testkit/CallingThreadDispatcherModelSpec.scala index 97480cb6d3..993f92259d 100644 --- a/akka-actor-tests/src/test/scala/akka/testkit/CallingThreadDispatcherModelSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/testkit/CallingThreadDispatcherModelSpec.scala @@ -7,8 +7,15 @@ class CallingThreadDispatcherModelSpec extends ActorModelSpec { import ActorModelSpec._ def newInterceptedDispatcher = new CallingThreadDispatcher with MessageDispatcherInterceptor + // A CallingThreadDispatcher can by design not process messages in parallel, + // so disable this test override def dispatcherShouldProcessMessagesInParallel {} + // This test needs to be adapted: CTD runs the flood completely sequentially + // with start, invocation, stop, schedule shutdown, abort shutdown, repeat; + // add "keeper" actor to lock down the dispatcher instance, since the + // frequent attempted shutdown seems rather costly (random timing failures + // without this fix) override def dispatcherShouldHandleWavesOfActors { implicit val dispatcher = newInterceptedDispatcher @@ -27,6 +34,7 @@ class CallingThreadDispatcherModelSpec extends ActorModelSpec { assertDispatcher(dispatcher)(starts = run, stops = run) } } + } -// vim: set ts=4 sw=4 et: +// vim: set ts=2 sw=2 et: diff --git a/akka-actor/src/main/scala/akka/AkkaException.scala b/akka-actor/src/main/scala/akka/AkkaException.scala index 748df1ced0..fe0bac916e 100644 --- a/akka-actor/src/main/scala/akka/AkkaException.scala +++ b/akka-actor/src/main/scala/akka/AkkaException.scala @@ -16,7 +16,7 @@ import java.net.{InetAddress, UnknownHostException} * * @author Jonas Bonér */ -class AkkaException(message: String = "") extends RuntimeException(message) with Serializable { +class AkkaException(message: String = "", cause: Throwable = null) extends RuntimeException(message, cause) with Serializable { val uuid = "%s_%s".format(AkkaException.hostname, newUuid) override lazy val toString = { diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index ee3c48374f..104283d853 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -67,12 +67,12 @@ case class MaximumNumberOfRestartsWithinTimeRangeReached( @BeanProperty val lastExceptionCausingRestart: Throwable) extends LifeCycleMessage // Exceptions for Actors -class ActorStartException private[akka](message: String) extends AkkaException(message) -class IllegalActorStateException private[akka](message: String) extends AkkaException(message) -class ActorKilledException private[akka](message: String) extends AkkaException(message) -class ActorInitializationException private[akka](message: String) extends AkkaException(message) -class ActorTimeoutException private[akka](message: String) extends AkkaException(message) -class InvalidMessageException private[akka](message: String) extends AkkaException(message) +class ActorStartException private[akka](message: String, cause: Throwable = null) extends AkkaException(message, cause) +class IllegalActorStateException private[akka](message: String, cause: Throwable = null) extends AkkaException(message, cause) +class ActorKilledException private[akka](message: String, cause: Throwable = null) extends AkkaException(message, cause) +class ActorInitializationException private[akka](message: String, cause: Throwable = null) extends AkkaException(message, cause) +class ActorTimeoutException private[akka](message: String, cause: Throwable = null) extends AkkaException(message, cause) +class InvalidMessageException private[akka](message: String, cause: Throwable = null) extends AkkaException(message, cause) /** * This message is thrown by default when an Actors behavior doesn't match a message @@ -125,7 +125,9 @@ object Actor extends ListenerManagement { */ type Receive = PartialFunction[Any, Unit] - private[actor] val actorRefInCreation = new scala.util.DynamicVariable[Option[ActorRef]](None) + private[actor] val actorRefInCreation = new ThreadLocal[Option[ActorRef]]{ + override def initialValue = None + } /** * Creates an ActorRef out of the Actor with type T. @@ -159,12 +161,15 @@ object Actor extends ListenerManagement { */ def actorOf(clazz: Class[_ <: Actor]): ActorRef = new LocalActorRef(() => { import ReflectiveAccess.{ createInstance, noParams, noArgs } - createInstance[Actor](clazz.asInstanceOf[Class[_]], noParams, noArgs).getOrElse( - throw new ActorInitializationException( - "Could not instantiate Actor" + + createInstance[Actor](clazz.asInstanceOf[Class[_]], noParams, noArgs) match { + case r: Right[Exception, Actor] => r.b + case l: Left[Exception, Actor] => throw new ActorInitializationException( + "Could not instantiate Actor of " + clazz + "\nMake sure Actor is NOT defined inside a class/trait," + "\nif so put it outside the class/trait, f.e. in a companion object," + - "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.")) + "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.", l.a) + } + }, None) /** @@ -290,7 +295,7 @@ trait Actor { * the 'forward' function. */ @transient implicit val someSelf: Some[ActorRef] = { - val optRef = Actor.actorRefInCreation.value + val optRef = Actor.actorRefInCreation.get if (optRef.isEmpty) throw new ActorInitializationException( "ActorRef for instance of actor [" + getClass.getName + "] is not in scope." + "\n\tYou can not create an instance of an actor explicitly using 'new MyActor'." + @@ -298,7 +303,7 @@ trait Actor { "\n\tEither use:" + "\n\t\t'val actor = Actor.actorOf[MyActor]', or" + "\n\t\t'val actor = Actor.actorOf(new MyActor(..))'") - Actor.actorRefInCreation.value = None + Actor.actorRefInCreation.set(None) optRef.asInstanceOf[Some[ActorRef]].get.id = getClass.getName //FIXME: Is this needed? optRef.asInstanceOf[Some[ActorRef]] } @@ -322,7 +327,7 @@ trait Actor { *
* For example fields like: *
- * self.dispactcher = ...
+ * self.dispatcher = ...
* self.trapExit = ...
* self.faultHandler = ...
* self.lifeCycle = ...
@@ -368,14 +373,14 @@ trait Actor {
*
* Is called when an Actor is started by invoking 'actor.start()'.
*/
- def preStart {}
+ def preStart() {}
/**
* User overridable callback.
*
* Is called when 'actor.stop()' is invoked.
*/
- def postStop {}
+ def postStop() {}
/**
* User overridable callback.
@@ -417,7 +422,7 @@ trait Actor {
}
/**
- * Changes tha Actor's behavior to become the new 'Receive' (PartialFunction[Any, Unit]) handler.
+ * Changes the Actor's behavior to become the new 'Receive' (PartialFunction[Any, Unit]) handler.
* Puts the behavior on top of the hotswap stack.
* If "discardOld" is true, an unbecome will be issued prior to pushing the new behavior to the stack
*/
diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala
index 6fa44452e0..08e99206c2 100644
--- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala
+++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala
@@ -279,7 +279,7 @@ trait ActorRef extends ActorRefShared with java.lang.Comparable[ActorRef] { scal
* Akka Java API.
* Sends a one-way asynchronous message. E.g. fire-and-forget semantics.
*
- * Allows you to pass along the sender of the messag.
+ * Allows you to pass along the sender of the message.
*
*
* actor.sendOneWay(message, context);
@@ -291,14 +291,14 @@ trait ActorRef extends ActorRefShared with java.lang.Comparable[ActorRef] { scal
/**
* Akka Java API.
* @see sendRequestReply(message: AnyRef, timeout: Long, sender: ActorRef)
- * Uses the defualt timeout of the Actor (setTimeout()) and omits the sender reference
+ * Uses the default timeout of the Actor (setTimeout()) and omits the sender reference
*/
def sendRequestReply(message: AnyRef): AnyRef = sendRequestReply(message, timeout, null)
/**
* Akka Java API.
* @see sendRequestReply(message: AnyRef, timeout: Long, sender: ActorRef)
- * Uses the defualt timeout of the Actor (setTimeout())
+ * Uses the default timeout of the Actor (setTimeout())
*/
def sendRequestReply(message: AnyRef, sender: ActorRef): AnyRef = sendRequestReply(message, timeout, sender)
@@ -1015,12 +1015,12 @@ class LocalActorRef private[akka] (
private[this] def newActor: Actor = {
try {
- Actor.actorRefInCreation.value = Some(this)
+ Actor.actorRefInCreation.set(Some(this))
val a = actorFactory()
if (a eq null) throw new ActorInitializationException("Actor instance passed to ActorRef can not be 'null'")
a
} finally {
- Actor.actorRefInCreation.value = None
+ Actor.actorRefInCreation.set(None)
}
}
diff --git a/akka-actor/src/main/scala/akka/actor/ActorRegistry.scala b/akka-actor/src/main/scala/akka/actor/ActorRegistry.scala
index 27057ce8a9..c833c6d360 100644
--- a/akka-actor/src/main/scala/akka/actor/ActorRegistry.scala
+++ b/akka-actor/src/main/scala/akka/actor/ActorRegistry.scala
@@ -36,7 +36,7 @@ case class ActorUnregistered(actor: ActorRef) extends ActorRegistryEvent
* @author Jonas Bonér
*/
-private[actor] final class ActorRegistry private[actor] () extends ListenerManagement {
+final class ActorRegistry private[actor] () extends ListenerManagement {
private val actorsByUUID = new ConcurrentHashMap[Uuid, ActorRef]
private val actorsById = new Index[String,ActorRef]
diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala
index 815ab1076c..f4fff52035 100644
--- a/akka-actor/src/main/scala/akka/actor/FSM.scala
+++ b/akka-actor/src/main/scala/akka/actor/FSM.scala
@@ -104,7 +104,7 @@ object FSM {
* different concerns in different places; you may choose to use
* when for describing the properties of a state, including of
* course initiating transitions, but you can describe the transitions using
- * onTransision to avoid having to duplicate that code among
+ * onTransition to avoid having to duplicate that code among
* multiple paths which lead to a transition:
*
*
diff --git a/akka-actor/src/main/scala/akka/actor/Scheduler.scala b/akka-actor/src/main/scala/akka/actor/Scheduler.scala
index cbda9d0af9..1c1da8e7a2 100644
--- a/akka-actor/src/main/scala/akka/actor/Scheduler.scala
+++ b/akka-actor/src/main/scala/akka/actor/Scheduler.scala
@@ -105,13 +105,17 @@ object Scheduler {
}
}
- def shutdown: Unit = synchronized {
- service.shutdown
+ def shutdown() {
+ synchronized {
+ service.shutdown()
+ }
}
- def restart: Unit = synchronized {
- shutdown
- service = Executors.newSingleThreadScheduledExecutor(SchedulerThreadFactory)
+ def restart() {
+ synchronized {
+ shutdown()
+ service = Executors.newSingleThreadScheduledExecutor(SchedulerThreadFactory)
+ }
}
}
diff --git a/akka-actor/src/main/scala/akka/actor/Supervisor.scala b/akka-actor/src/main/scala/akka/actor/Supervisor.scala
index e32b515ae5..50071524dc 100644
--- a/akka-actor/src/main/scala/akka/actor/Supervisor.scala
+++ b/akka-actor/src/main/scala/akka/actor/Supervisor.scala
@@ -13,7 +13,7 @@ import java.util.concurrent.{CopyOnWriteArrayList, ConcurrentHashMap}
import java.net.InetSocketAddress
import akka.config.Supervision._
-class SupervisorException private[akka](message: String) extends AkkaException(message)
+class SupervisorException private[akka](message: String, cause: Throwable = null) extends AkkaException(message, cause)
/**
* Factory object for creating supervisors declarative. It creates instances of the 'Supervisor' class.
diff --git a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala
index 77500d4059..71904288ef 100644
--- a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala
+++ b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala
@@ -24,7 +24,7 @@ import akka.japi.{Creator, Procedure}
*
* } else if (msg.equals("UseSender") && getContext().getSender().isDefined()) {
* // Reply to original sender of message using the sender reference
- * // also passing along my own refererence (the context)
+ * // also passing along my own reference (the context)
* getContext().getSender().get().sendOneWay(msg, context);
*
* } else if (msg.equals("UseSenderFuture") && getContext().getSenderFuture().isDefined()) {
@@ -36,7 +36,7 @@ import akka.japi.{Creator, Procedure}
* getContext().sendOneWay(msg)
*
* } else if (msg.equals("ForwardMessage")) {
- * // Retreive an actor from the ActorRegistry by ID and get an ActorRef back
+ * // Retrieve an actor from the ActorRegistry by ID and get an ActorRef back
* ActorRef actorRef = Actor.registry.actorsFor("some-actor-id").head();
*
* } else throw new IllegalArgumentException("Unknown message: " + message);
@@ -88,14 +88,14 @@ abstract class UntypedActor extends Actor {
*
* Is called when an Actor is started by invoking 'actor.start()'.
*/
- override def preStart {}
+ override def preStart() {}
/**
* User overridable callback.
*
* Is called when 'actor.stop()' is invoked.
*/
- override def postStop {}
+ override def postStop() {}
/**
* User overridable callback.
diff --git a/akka-actor/src/main/scala/akka/config/Config.scala b/akka-actor/src/main/scala/akka/config/Config.scala
index 7d50e59cd7..1b5d8f774e 100644
--- a/akka-actor/src/main/scala/akka/config/Config.scala
+++ b/akka-actor/src/main/scala/akka/config/Config.scala
@@ -6,8 +6,8 @@ package akka.config
import akka.AkkaException
-class ConfigurationException(message: String) extends AkkaException(message)
-class ModuleNotAvailableException(message: String) extends AkkaException(message)
+class ConfigurationException(message: String, cause: Throwable = null) extends AkkaException(message, cause)
+class ModuleNotAvailableException(message: String, cause: Throwable = null) extends AkkaException(message, cause)
/**
* Loads up the configuration (from the akka.conf file).
diff --git a/akka-actor/src/main/scala/akka/config/Configuration.scala b/akka-actor/src/main/scala/akka/config/Configuration.scala
index aabdc5962f..d06a9eb88e 100644
--- a/akka-actor/src/main/scala/akka/config/Configuration.scala
+++ b/akka-actor/src/main/scala/akka/config/Configuration.scala
@@ -64,6 +64,24 @@ class Configuration(val map: Map[String, Any]) {
def keys: Iterable[String] = map.keys
+ def getAny(key: String): Option[Any] = {
+ try {
+ Some(map(key))
+ } catch {
+ case _ => None
+ }
+ }
+
+ def getAny(key: String, defaultValue: Any): Any = getAny(key).getOrElse(defaultValue)
+
+ def getSeqAny(key: String): Seq[Any] = {
+ try {
+ map(key).asInstanceOf[Seq[Any]]
+ } catch {
+ case _ => Seq.empty[Any]
+ }
+ }
+
def getString(key: String): Option[String] = map.get(key).map(_.toString)
def getString(key: String, defaultValue: String): String = getString(key).getOrElse(defaultValue)
diff --git a/akka-actor/src/main/scala/akka/dataflow/DataFlow.scala b/akka-actor/src/main/scala/akka/dataflow/DataFlow.scala
index 7ac900333d..258bc4fff0 100644
--- a/akka-actor/src/main/scala/akka/dataflow/DataFlow.scala
+++ b/akka-actor/src/main/scala/akka/dataflow/DataFlow.scala
@@ -23,7 +23,7 @@ object DataFlow {
object Start
object Exit
- class DataFlowVariableException(msg: String) extends AkkaException(msg)
+ class DataFlowVariableException(message: String, cause: Throwable = null) extends AkkaException(message, cause)
/**
* Executes the supplied thunk in another thread.
@@ -160,6 +160,6 @@ object DataFlow {
}
}
- def shutdown = in ! Exit
+ def shutdown() { in ! Exit }
}
}
diff --git a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala
index 04ff6a9504..eee5d53c51 100644
--- a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala
@@ -187,14 +187,14 @@ object Dispatchers {
case "GlobalExecutorBasedEventDriven" => GlobalExecutorBasedEventDrivenDispatcherConfigurator
case fqn =>
ReflectiveAccess.getClassFor[MessageDispatcherConfigurator](fqn) match {
- case Some(clazz) =>
- val instance = ReflectiveAccess.createInstance[MessageDispatcherConfigurator](clazz, Array[Class[_]](), Array[AnyRef]())
- if (instance.isEmpty)
- throw new IllegalArgumentException("Cannot instantiate MessageDispatcherConfigurator type [%s], make sure it has a default no-args constructor" format fqn)
- else
- instance.get
- case None =>
- throw new IllegalArgumentException("Unknown MessageDispatcherConfigurator type [%s]" format fqn)
+ case r: Right[_, Class[MessageDispatcherConfigurator]] =>
+ ReflectiveAccess.createInstance[MessageDispatcherConfigurator](r.b, Array[Class[_]](), Array[AnyRef]()) match {
+ case r: Right[Exception, MessageDispatcherConfigurator] => r.b
+ case l: Left[Exception, MessageDispatcherConfigurator] =>
+ throw new IllegalArgumentException("Cannot instantiate MessageDispatcherConfigurator type [%s], make sure it has a default no-args constructor" format fqn, l.a)
+ }
+ case l: Left[Exception, _] =>
+ throw new IllegalArgumentException("Unknown MessageDispatcherConfigurator type [%s]" format fqn, l.a)
}
} map {
_ configure cfg
diff --git a/akka-actor/src/main/scala/akka/dispatch/ExecutorBasedEventDrivenDispatcher.scala b/akka-actor/src/main/scala/akka/dispatch/ExecutorBasedEventDrivenDispatcher.scala
index 261a4c8170..dca2f2f822 100644
--- a/akka-actor/src/main/scala/akka/dispatch/ExecutorBasedEventDrivenDispatcher.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/ExecutorBasedEventDrivenDispatcher.scala
@@ -63,7 +63,7 @@ import java.util.concurrent.{ TimeUnit, ExecutorService, RejectedExecutionExcept
* @param throughput positive integer indicates the dispatcher will only process so much messages at a time from the
* mailbox, without checking the mailboxes of other actors. Zero or negative means the dispatcher
* always continues until the mailbox is empty.
- * Larger values (or zero or negative) increase througput, smaller values increase fairness
+ * Larger values (or zero or negative) increase throughput, smaller values increase fairness
*/
class ExecutorBasedEventDrivenDispatcher(
_name: String,
@@ -99,7 +99,7 @@ class ExecutorBasedEventDrivenDispatcher(
registerForExecution(mbox)
}
- private[akka] def executeFuture(invocation: FutureInvocation): Unit = if (active.isOn) {
+ private[akka] def executeFuture(invocation: FutureInvocation[_]): Unit = if (active.isOn) {
try executorService.get() execute invocation
catch {
case e: RejectedExecutionException =>
@@ -117,20 +117,14 @@ class ExecutorBasedEventDrivenDispatcher(
def createMailbox(actorRef: ActorRef): AnyRef = mailboxType match {
case b: UnboundedMailbox =>
- if (b.blocking) {
- new DefaultUnboundedMessageQueue(true) with ExecutableMailbox {
- final def dispatcher = ExecutorBasedEventDrivenDispatcher.this
- }
- } else { //If we have an unbounded, non-blocking mailbox, we can go lockless
- new ConcurrentLinkedQueue[MessageInvocation] with MessageQueue with ExecutableMailbox {
- final def dispatcher = ExecutorBasedEventDrivenDispatcher.this
- final def enqueue(m: MessageInvocation) = this.add(m)
- final def dequeue(): MessageInvocation = this.poll()
- }
+ new ConcurrentLinkedQueue[MessageInvocation] with MessageQueue with ExecutableMailbox {
+ @inline final def dispatcher = ExecutorBasedEventDrivenDispatcher.this
+ @inline final def enqueue(m: MessageInvocation) = this.add(m)
+ @inline final def dequeue(): MessageInvocation = this.poll()
}
case b: BoundedMailbox =>
- new DefaultBoundedMessageQueue(b.capacity, b.pushTimeOut, b.blocking) with ExecutableMailbox {
- final def dispatcher = ExecutorBasedEventDrivenDispatcher.this
+ new DefaultBoundedMessageQueue(b.capacity, b.pushTimeOut) with ExecutableMailbox {
+ @inline final def dispatcher = ExecutorBasedEventDrivenDispatcher.this
}
}
@@ -294,13 +288,13 @@ trait PriorityMailbox { self: ExecutorBasedEventDrivenDispatcher =>
override def createMailbox(actorRef: ActorRef): AnyRef = self.mailboxType match {
case b: UnboundedMailbox =>
- new UnboundedPriorityMessageQueue(b.blocking, comparator) with ExecutableMailbox {
- final def dispatcher = self
+ new UnboundedPriorityMessageQueue(comparator) with ExecutableMailbox {
+ @inline final def dispatcher = self
}
case b: BoundedMailbox =>
- new BoundedPriorityMessageQueue(b.capacity, b.pushTimeOut, b.blocking, comparator) with ExecutableMailbox {
- final def dispatcher = self
+ new BoundedPriorityMessageQueue(b.capacity, b.pushTimeOut, comparator) with ExecutableMailbox {
+ @inline final def dispatcher = self
}
}
}
diff --git a/akka-actor/src/main/scala/akka/dispatch/ExecutorBasedEventDrivenWorkStealingDispatcher.scala b/akka-actor/src/main/scala/akka/dispatch/ExecutorBasedEventDrivenWorkStealingDispatcher.scala
index f2f63a3ff4..7829e47712 100644
--- a/akka-actor/src/main/scala/akka/dispatch/ExecutorBasedEventDrivenWorkStealingDispatcher.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/ExecutorBasedEventDrivenWorkStealingDispatcher.scala
@@ -10,6 +10,7 @@ import akka.util.{ReflectiveAccess, Switch}
import java.util.Queue
import java.util.concurrent.atomic.{AtomicReference, AtomicInteger}
import java.util.concurrent.{ TimeUnit, ExecutorService, RejectedExecutionException, ConcurrentLinkedQueue, LinkedBlockingQueue}
+import util.DynamicVariable
/**
* An executor based event driven dispatcher which will try to redistribute work from busy actors to idle actors. It is assumed
@@ -55,6 +56,7 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(
@volatile private var actorType: Option[Class[_]] = None
@volatile private var members = Vector[ActorRef]()
+ private val donationInProgress = new DynamicVariable(false)
private[akka] override def register(actorRef: ActorRef) = {
//Verify actor type conformity
@@ -78,18 +80,22 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(
override private[akka] def dispatch(invocation: MessageInvocation) = {
val mbox = getMailbox(invocation.receiver)
- /*if (!mbox.isEmpty && attemptDonationOf(invocation, mbox)) {
+ if (donationInProgress.value == false && (!mbox.isEmpty || mbox.dispatcherLock.locked) && attemptDonationOf(invocation, mbox)) {
//We were busy and we got to donate the message to some other lucky guy, we're done here
- } else {*/
+ } else {
mbox enqueue invocation
registerForExecution(mbox)
- //}
+ }
}
override private[akka] def reRegisterForExecution(mbox: MessageQueue with ExecutableMailbox): Unit = {
- while(donateFrom(mbox)) {} //When we reregister, first donate messages to another actor
+ try {
+ donationInProgress.value = true
+ while(donateFrom(mbox)) {} //When we reregister, first donate messages to another actor
+ } finally { donationInProgress.value = false }
+
if (!mbox.isEmpty) //If we still have messages left to process, reschedule for execution
- super.reRegisterForExecution(mbox)
+ super.reRegisterForExecution(mbox)
}
/**
@@ -110,13 +116,14 @@ class ExecutorBasedEventDrivenWorkStealingDispatcher(
/**
* Returns true if the donation succeeded or false otherwise
*/
- /*protected def attemptDonationOf(message: MessageInvocation, donorMbox: MessageQueue with ExecutableMailbox): Boolean = {
+ protected def attemptDonationOf(message: MessageInvocation, donorMbox: MessageQueue with ExecutableMailbox): Boolean = try {
+ donationInProgress.value = true
val actors = members // copy to prevent concurrent modifications having any impact
doFindDonorRecipient(donorMbox, actors, System.identityHashCode(message) % actors.size) match {
case null => false
case recipient => donate(message, recipient)
}
- }*/
+ } finally { donationInProgress.value = false }
/**
* Rewrites the message and adds that message to the recipients mailbox
diff --git a/akka-actor/src/main/scala/akka/dispatch/Future.scala b/akka-actor/src/main/scala/akka/dispatch/Future.scala
index 762beb8ba3..9e657e15fa 100644
--- a/akka-actor/src/main/scala/akka/dispatch/Future.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/Future.scala
@@ -6,8 +6,8 @@ package akka.dispatch
import akka.AkkaException
import akka.event.EventHandler
-import akka.actor.Actor
-import akka.routing.Dispatcher
+import akka.actor.{Actor, Channel}
+import akka.util.Duration
import akka.japi.{ Procedure, Function => JFunc }
import scala.util.continuations._
@@ -15,12 +15,13 @@ import scala.util.continuations._
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent. {ConcurrentLinkedQueue, TimeUnit, Callable}
import java.util.concurrent.TimeUnit.{NANOSECONDS => NANOS, MILLISECONDS => MILLIS}
-import java.util.concurrent.atomic. {AtomicBoolean, AtomicInteger}
+import java.util.concurrent.atomic. {AtomicBoolean}
import java.lang.{Iterable => JIterable}
import java.util.{LinkedList => JLinkedList}
+import scala.collection.mutable.Stack
import annotation.tailrec
-class FutureTimeoutException(message: String) extends AkkaException(message)
+class FutureTimeoutException(message: String, cause: Throwable = null) extends AkkaException(message, cause)
object Futures {
@@ -234,12 +235,22 @@ object Future {
* This method constructs and returns a Future that will eventually hold the result of the execution of the supplied body
* The execution is performed by the specified Dispatcher.
*/
- def apply[T](body: => T, timeout: Long = Actor.TIMEOUT)(implicit dispatcher: MessageDispatcher): Future[T] = {
- val f = new DefaultCompletableFuture[T](timeout)
- dispatcher.dispatchFuture(FutureInvocation(f.asInstanceOf[CompletableFuture[Any]], () => body))
- f
+ def apply[T](body: => T, timeout: Long = Actor.TIMEOUT)(implicit dispatcher: MessageDispatcher): Future[T] =
+ dispatcher.dispatchFuture(() => body, timeout)
+
+ /**
+ * Construct a completable channel
+ */
+ def channel(timeout: Long = Actor.TIMEOUT) = new Channel[Any] {
+ val future = empty[Any](timeout)
+ def !(msg: Any) = future << msg
}
+ /**
+ * Create an empty Future with default timeout
+ */
+ def empty[T](timeout : Long = Actor.TIMEOUT) = new DefaultCompletableFuture[T](timeout)
+
import scala.collection.mutable.Builder
import scala.collection.generic.CanBuildFrom
@@ -282,6 +293,10 @@ object Future {
*/
def flow[A](body: => A @cps[Future[A]], timeout: Long = Actor.TIMEOUT): Future[A] =
reset(new DefaultCompletableFuture[A](timeout).completeWithResult(body))
+
+ private[akka] val callbacksPendingExecution = new ThreadLocal[Option[Stack[() => Unit]]]() {
+ override def initialValue = None
+ }
}
sealed trait Future[+T] {
@@ -315,11 +330,20 @@ sealed trait Future[+T] {
*/
def await : Future[T]
+ /**
+ * Blocks the current thread until the Future has been completed or the
+ * timeout has expired. The timeout will be the least value of 'atMost' and the timeout
+ * supplied at the constructuion of this Future.
+ * In the case of the timeout expiring a FutureTimeoutException will be thrown.
+ */
+ def await(atMost: Duration) : Future[T]
+
/**
* Blocks the current thread until the Future has been completed. Use
* caution with this method as it ignores the timeout and will block
* indefinitely if the Future is never completed.
*/
+ @deprecated("Will be removed after 1.1, it's dangerous and can cause deadlocks, agony and insanity.")
def awaitBlocking : Future[T]
/**
@@ -357,24 +381,6 @@ sealed trait Future[+T] {
else None
}
- /**
- * Waits for the completion of this Future, then returns the completed value.
- * If the Future's timeout expires while waiting a FutureTimeoutException
- * will be thrown.
- *
- * Equivalent to calling future.await.value.
- */
- def awaitValue: Option[Either[Throwable, T]]
-
- /**
- * Returns the result of the Future if one is available within the specified
- * time, if the time left on the future is less than the specified time, the
- * time left on the future will be used instead of the specified time.
- * returns None if no result, Some(Right(t)) if a result, or
- * Some(Left(error)) if there was an exception
- */
- def valueWithin(time: Long, unit: TimeUnit): Option[Either[Throwable, T]]
-
/**
* Returns the contained exception of this Future if it exists.
*/
@@ -387,12 +393,12 @@ sealed trait Future[+T] {
/**
* When this Future is completed, apply the provided function to the
* Future. If the Future has already been completed, this will apply
- * immediatly.
+ * immediately.
*/
def onComplete(func: Future[T] => Unit): Future[T]
/**
- * When the future is compeleted with a valid result, apply the provided
+ * When the future is completed with a valid result, apply the provided
* PartialFunction to the result.
*
* val result = future receive {
@@ -670,45 +676,34 @@ class DefaultCompletableFuture[T](timeout: Long, timeunit: TimeUnit) extends Com
private var _value: Option[Either[Throwable, T]] = None
private var _listeners: List[Future[T] => Unit] = Nil
+ /**
+ * Must be called inside _lock.lock<->_lock.unlock
+ */
@tailrec
- private def awaitUnsafe(wait: Long): Boolean = {
- if (_value.isEmpty && wait > 0) {
+ private def awaitUnsafe(waitTimeNanos: Long): Boolean = {
+ if (_value.isEmpty && waitTimeNanos > 0) {
val start = currentTimeInNanos
- val remaining = try {
- _signal.awaitNanos(wait)
+ val remainingNanos = try {
+ _signal.awaitNanos(waitTimeNanos)
} catch {
case e: InterruptedException =>
- wait - (currentTimeInNanos - start)
+ waitTimeNanos - (currentTimeInNanos - start)
}
- awaitUnsafe(remaining)
+ awaitUnsafe(remainingNanos)
} else {
_value.isDefined
}
}
- def awaitValue: Option[Either[Throwable, T]] = {
+ def await(atMost: Duration) = {
_lock.lock
- try {
- awaitUnsafe(timeoutInNanos - (currentTimeInNanos - _startTimeInNanos))
- _value
- } finally {
- _lock.unlock
- }
- }
-
- def valueWithin(time: Long, unit: TimeUnit): Option[Either[Throwable, T]] = {
- _lock.lock
- try {
- awaitUnsafe(unit.toNanos(time).min(timeoutInNanos - (currentTimeInNanos - _startTimeInNanos)))
- _value
- } finally {
- _lock.unlock
- }
+ if (try { awaitUnsafe(atMost.toNanos min timeLeft()) } finally { _lock.unlock }) this
+ else throw new FutureTimeoutException("Futures timed out after [" + NANOS.toMillis(timeoutInNanos) + "] milliseconds")
}
def await = {
_lock.lock
- if (try { awaitUnsafe(timeoutInNanos - (currentTimeInNanos - _startTimeInNanos)) } finally { _lock.unlock }) this
+ if (try { awaitUnsafe(timeLeft()) } finally { _lock.unlock }) this
else throw new FutureTimeoutException("Futures timed out after [" + NANOS.toMillis(timeoutInNanos) + "] milliseconds")
}
@@ -724,7 +719,7 @@ class DefaultCompletableFuture[T](timeout: Long, timeunit: TimeUnit) extends Com
}
}
- def isExpired: Boolean = timeoutInNanos - (currentTimeInNanos - _startTimeInNanos) <= 0
+ def isExpired: Boolean = timeLeft() <= 0
def value: Option[Either[Throwable, T]] = {
_lock.lock
@@ -738,7 +733,7 @@ class DefaultCompletableFuture[T](timeout: Long, timeunit: TimeUnit) extends Com
def complete(value: Either[Throwable, T]): DefaultCompletableFuture[T] = {
_lock.lock
val notifyTheseListeners = try {
- if (_value.isEmpty) {
+ if (_value.isEmpty && !isExpired) { //Only complete if we aren't expired
_value = Some(value)
val existingListeners = _listeners
_listeners = Nil
@@ -749,8 +744,29 @@ class DefaultCompletableFuture[T](timeout: Long, timeunit: TimeUnit) extends Com
_lock.unlock
}
- if (notifyTheseListeners.nonEmpty)
- notifyTheseListeners.reverse foreach notify
+ if (notifyTheseListeners.nonEmpty) { // Steps to ensure we don't run into a stack-overflow situation
+ @tailrec def runCallbacks(rest: List[Future[T] => Unit], callbacks: Stack[() => Unit]) {
+ if (rest.nonEmpty) {
+ notifyCompleted(rest.head)
+ while (callbacks.nonEmpty) { callbacks.pop().apply() }
+ runCallbacks(rest.tail, callbacks)
+ }
+ }
+
+ val pending = Future.callbacksPendingExecution.get
+ if (pending.isDefined) { //Instead of nesting the calls to the callbacks (leading to stack overflow)
+ pending.get.push(() => { // Linearize/aggregate callbacks at top level and then execute
+ val doNotify = notifyCompleted _ //Hoist closure to avoid garbage
+ notifyTheseListeners foreach doNotify
+ })
+ } else {
+ try {
+ val callbacks = Stack[() => Unit]() // Allocate new aggregator for pending callbacks
+ Future.callbacksPendingExecution.set(Some(callbacks)) // Specify the callback aggregator
+ runCallbacks(notifyTheseListeners, callbacks) // Execute callbacks, if they trigger new callbacks, they are aggregated
+ } finally { Future.callbacksPendingExecution.set(None) } // Ensure cleanup
+ }
+ }
this
}
@@ -759,19 +775,21 @@ class DefaultCompletableFuture[T](timeout: Long, timeunit: TimeUnit) extends Com
_lock.lock
val notifyNow = try {
if (_value.isEmpty) {
- _listeners ::= func
- false
+ if(!isExpired) { //Only add the listener if the future isn't expired
+ _listeners ::= func
+ false
+ } else false //Will never run the callback since the future is expired
} else true
} finally {
_lock.unlock
}
- if (notifyNow) notify(func)
+ if (notifyNow) notifyCompleted(func)
this
}
- private def notify(func: Future[T] => Unit) {
+ private def notifyCompleted(func: Future[T] => Unit) {
try {
func(this)
} catch {
@@ -779,7 +797,8 @@ class DefaultCompletableFuture[T](timeout: Long, timeunit: TimeUnit) extends Com
}
}
- private def currentTimeInNanos: Long = MILLIS.toNanos(System.currentTimeMillis)
+ @inline private def currentTimeInNanos: Long = MILLIS.toNanos(System.currentTimeMillis)
+ @inline private def timeLeft(): Long = timeoutInNanos - (currentTimeInNanos - _startTimeInNanos)
}
/**
@@ -791,8 +810,7 @@ sealed class AlreadyCompletedFuture[T](suppliedValue: Either[Throwable, T]) exte
def complete(value: Either[Throwable, T]): CompletableFuture[T] = this
def onComplete(func: Future[T] => Unit): Future[T] = { func(this); this }
- def awaitValue: Option[Either[Throwable, T]] = value
- def valueWithin(time: Long, unit: TimeUnit): Option[Either[Throwable, T]] = value
+ def await(atMost: Duration): Future[T] = this
def await : Future[T] = this
def awaitBlocking : Future[T] = this
def isExpired: Boolean = true
diff --git a/akka-actor/src/main/scala/akka/dispatch/MailboxHandling.scala b/akka-actor/src/main/scala/akka/dispatch/MailboxHandling.scala
index e0586a40a7..388d8f10b0 100644
--- a/akka-actor/src/main/scala/akka/dispatch/MailboxHandling.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/MailboxHandling.scala
@@ -11,7 +11,7 @@ import java.util.{Queue, List, Comparator, PriorityQueue}
import java.util.concurrent._
import akka.util._
-class MessageQueueAppendFailedException(message: String) extends AkkaException(message)
+class MessageQueueAppendFailedException(message: String, cause: Throwable = null) extends AkkaException(message, cause)
/**
* @author Jonas Bonér
@@ -30,9 +30,8 @@ trait MessageQueue {
*/
sealed trait MailboxType
-case class UnboundedMailbox(val blocking: Boolean = false) extends MailboxType
+case class UnboundedMailbox() extends MailboxType
case class BoundedMailbox(
- val blocking: Boolean = false,
val capacity: Int = { if (Dispatchers.MAILBOX_CAPACITY < 0) Int.MaxValue else Dispatchers.MAILBOX_CAPACITY },
val pushTimeOut: Duration = Dispatchers.MAILBOX_PUSH_TIME_OUT) extends MailboxType {
if (capacity < 0) throw new IllegalArgumentException("The capacity for BoundedMailbox can not be negative")
@@ -40,46 +39,35 @@ case class BoundedMailbox(
}
trait UnboundedMessageQueueSemantics extends MessageQueue { self: BlockingQueue[MessageInvocation] =>
- def blockDequeue: Boolean
-
- final def enqueue(handle: MessageInvocation) {
- this add handle
- }
-
- final def dequeue(): MessageInvocation = {
- if (blockDequeue) this.take()
- else this.poll()
- }
+ @inline final def enqueue(handle: MessageInvocation): Unit = this add handle
+ @inline final def dequeue(): MessageInvocation = this.poll()
}
trait BoundedMessageQueueSemantics extends MessageQueue { self: BlockingQueue[MessageInvocation] =>
- def blockDequeue: Boolean
def pushTimeOut: Duration
final def enqueue(handle: MessageInvocation) {
- if (pushTimeOut.length > 0 && pushTimeOut.toMillis > 0) {
- if (!this.offer(handle, pushTimeOut.length, pushTimeOut.unit))
- throw new MessageQueueAppendFailedException("Couldn't enqueue message " + handle + " to " + toString)
+ if (pushTimeOut.length > 0) {
+ this.offer(handle, pushTimeOut.length, pushTimeOut.unit) || {
+ throw new MessageQueueAppendFailedException("Couldn't enqueue message " + handle + " to " + toString) }
} else this put handle
}
- final def dequeue(): MessageInvocation =
- if (blockDequeue) this.take()
- else this.poll()
+ @inline final def dequeue(): MessageInvocation = this.poll()
}
-class DefaultUnboundedMessageQueue(val blockDequeue: Boolean) extends
+class DefaultUnboundedMessageQueue extends
LinkedBlockingQueue[MessageInvocation] with
UnboundedMessageQueueSemantics
-class DefaultBoundedMessageQueue(capacity: Int, val pushTimeOut: Duration, val blockDequeue: Boolean) extends
+class DefaultBoundedMessageQueue(capacity: Int, val pushTimeOut: Duration) extends
LinkedBlockingQueue[MessageInvocation](capacity) with
BoundedMessageQueueSemantics
-class UnboundedPriorityMessageQueue(val blockDequeue: Boolean, cmp: Comparator[MessageInvocation]) extends
+class UnboundedPriorityMessageQueue(cmp: Comparator[MessageInvocation]) extends
PriorityBlockingQueue[MessageInvocation](11, cmp) with
UnboundedMessageQueueSemantics
-class BoundedPriorityMessageQueue(capacity: Int, val pushTimeOut: Duration, val blockDequeue: Boolean, cmp: Comparator[MessageInvocation]) extends
- BoundedBlockingQueue[MessageInvocation](capacity, new PriorityQueue[MessageInvocation](11, cmp)) with
- BoundedMessageQueueSemantics
+class BoundedPriorityMessageQueue(capacity: Int, val pushTimeOut: Duration, cmp: Comparator[MessageInvocation]) extends
+ BoundedBlockingQueue[MessageInvocation](capacity, new PriorityQueue[MessageInvocation](11, cmp)) with
+ BoundedMessageQueueSemantics
diff --git a/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala b/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala
index 374b3b4b45..415ed053dc 100644
--- a/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala
@@ -5,11 +5,11 @@
package akka.dispatch
import java.util.concurrent._
-import atomic. {AtomicInteger, AtomicBoolean, AtomicReference, AtomicLong}
+import java.util.concurrent.atomic.AtomicLong
import akka.event.EventHandler
import akka.config.Configuration
import akka.config.Config.TIME_UNIT
-import akka.util.{Duration, Switch, ReentrantGuard, HashCode, ReflectiveAccess}
+import akka.util.{Duration, Switch, ReentrantGuard}
import java.util.concurrent.ThreadPoolExecutor.{AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy, DiscardPolicy}
import akka.actor._
@@ -30,16 +30,18 @@ final case class MessageInvocation(val receiver: ActorRef,
}
}
-final case class FutureInvocation(future: CompletableFuture[Any], function: () => Any) extends Runnable {
- val uuid = akka.actor.newUuid
-
- def run = future complete (try {
- Right(function.apply)
- } catch {
- case e =>
- EventHandler.error(e, this, e.getMessage)
- Left(e)
- })
+final case class FutureInvocation[T](future: CompletableFuture[T], function: () => T, cleanup: () => Unit) extends Runnable {
+ def run = {
+ future complete (try {
+ Right(function())
+ } catch {
+ case e =>
+ EventHandler.error(e, this, e.getMessage)
+ Left(e)
+ } finally {
+ cleanup()
+ })
+ }
}
object MessageDispatcher {
@@ -57,7 +59,7 @@ trait MessageDispatcher {
import MessageDispatcher._
protected val uuids = new ConcurrentSkipListSet[Uuid]
- protected val futures = new ConcurrentSkipListSet[Uuid]
+ protected val futures = new AtomicLong(0L)
protected val guard = new ReentrantGuard
protected val active = new Switch(false)
@@ -84,15 +86,27 @@ trait MessageDispatcher {
private[akka] final def dispatchMessage(invocation: MessageInvocation): Unit = dispatch(invocation)
- private[akka] final def dispatchFuture(invocation: FutureInvocation): Unit = {
- guard withGuard {
- futures add invocation.uuid
- if (active.isOff) { active.switchOn { start } }
+ private[akka] final def dispatchFuture[T](block: () => T, timeout: Long): Future[T] = {
+ futures.getAndIncrement()
+ try {
+ val future = new DefaultCompletableFuture[T](timeout)
+
+ if (active.isOff)
+ guard withGuard { active.switchOn { start } }
+
+ executeFuture(FutureInvocation[T](future, block, futureCleanup))
+ future
+ } catch {
+ case e =>
+ futures.decrementAndGet
+ throw e
}
- invocation.future.onComplete { f =>
+ }
+
+ private val futureCleanup: () => Unit =
+ () => if (futures.decrementAndGet() == 0) {
guard withGuard {
- futures remove invocation.uuid
- if (futures.isEmpty && uuids.isEmpty) {
+ if (futures.get == 0 && uuids.isEmpty) {
shutdownSchedule match {
case UNSCHEDULED =>
shutdownSchedule = SCHEDULED
@@ -104,8 +118,6 @@ trait MessageDispatcher {
}
}
}
- executeFuture(invocation)
- }
private[akka] def register(actorRef: ActorRef) {
if (actorRef.mailbox eq null)
@@ -122,7 +134,7 @@ trait MessageDispatcher {
private[akka] def unregister(actorRef: ActorRef) = {
if (uuids remove actorRef.uuid) {
actorRef.mailbox = null
- if (uuids.isEmpty && futures.isEmpty){
+ if (uuids.isEmpty && futures.get == 0){
shutdownSchedule match {
case UNSCHEDULED =>
shutdownSchedule = SCHEDULED
@@ -156,7 +168,7 @@ trait MessageDispatcher {
shutdownSchedule = SCHEDULED
Scheduler.scheduleOnce(this, timeoutMs, TimeUnit.MILLISECONDS)
case SCHEDULED =>
- if (uuids.isEmpty() && futures.isEmpty) {
+ if (uuids.isEmpty && futures.get == 0) {
active switchOff {
shutdown // shut down in the dispatcher's references is zero
}
@@ -188,17 +200,17 @@ trait MessageDispatcher {
*/
private[akka] def dispatch(invocation: MessageInvocation): Unit
- private[akka] def executeFuture(invocation: FutureInvocation): Unit
+ private[akka] def executeFuture(invocation: FutureInvocation[_]): Unit
/**
* Called one time every time an actor is attached to this dispatcher and this dispatcher was previously shutdown
*/
- private[akka] def start: Unit
+ private[akka] def start(): Unit
/**
* Called one time every time an actor is detached from this dispatcher and this dispatcher has no actors left attached
*/
- private[akka] def shutdown: Unit
+ private[akka] def shutdown(): Unit
/**
* Returns the size of the mailbox for the specified actor
@@ -206,9 +218,9 @@ trait MessageDispatcher {
def mailboxSize(actorRef: ActorRef): Int
/**
- * Returns the size of the Future queue
+ * Returns the amount of futures queued for execution
*/
- def futureQueueSize: Int = futures.size
+ def pendingFutures: Long = futures.get
}
/**
@@ -222,9 +234,8 @@ abstract class MessageDispatcherConfigurator {
def mailboxType(config: Configuration): MailboxType = {
val capacity = config.getInt("mailbox-capacity", Dispatchers.MAILBOX_CAPACITY)
- // FIXME how do we read in isBlocking for mailbox? Now set to 'false'.
if (capacity < 1) UnboundedMailbox()
- else BoundedMailbox(false, capacity, Duration(config.getInt("mailbox-push-timeout-time", Dispatchers.MAILBOX_PUSH_TIME_OUT.toMillis.toInt), TIME_UNIT))
+ else BoundedMailbox(capacity, Duration(config.getInt("mailbox-push-timeout-time", Dispatchers.MAILBOX_PUSH_TIME_OUT.toMillis.toInt), TIME_UNIT))
}
def configureThreadPool(config: Configuration, createDispatcher: => (ThreadPoolConfig) => MessageDispatcher): ThreadPoolConfigDispatcherBuilder = {
diff --git a/akka-actor/src/main/scala/akka/dispatch/ThreadBasedDispatcher.scala b/akka-actor/src/main/scala/akka/dispatch/ThreadBasedDispatcher.scala
index a8dfcf5860..9ed0ce8ef1 100644
--- a/akka-actor/src/main/scala/akka/dispatch/ThreadBasedDispatcher.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/ThreadBasedDispatcher.scala
@@ -25,13 +25,13 @@ class ThreadBasedDispatcher(_actor: ActorRef, _mailboxType: MailboxType)
private[akka] val owner = new AtomicReference[ActorRef](_actor)
def this(actor: ActorRef) =
- this(actor, UnboundedMailbox(true)) // For Java API
+ this(actor, UnboundedMailbox()) // For Java API
def this(actor: ActorRef, capacity: Int) =
- this(actor, BoundedMailbox(true, capacity)) //For Java API
+ this(actor, BoundedMailbox(capacity)) //For Java API
def this(actor: ActorRef, capacity: Int, pushTimeOut: Duration) = //For Java API
- this(actor, BoundedMailbox(true, capacity, pushTimeOut))
+ this(actor, BoundedMailbox(capacity, pushTimeOut))
override def register(actorRef: ActorRef) = {
val actor = owner.get()
diff --git a/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala b/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala
index 83c30f23e0..0bcc0662e0 100644
--- a/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala
@@ -221,9 +221,9 @@ trait ExecutorServiceDelegate extends ExecutorService {
def execute(command: Runnable) = executor.execute(command)
- def shutdown = executor.shutdown
+ def shutdown() { executor.shutdown() }
- def shutdownNow = executor.shutdownNow
+ def shutdownNow() = executor.shutdownNow()
def isShutdown = executor.isShutdown
diff --git a/akka-actor/src/main/scala/akka/event/EventHandler.scala b/akka-actor/src/main/scala/akka/event/EventHandler.scala
index 9d53b57787..15dd7eaa30 100644
--- a/akka-actor/src/main/scala/akka/event/EventHandler.scala
+++ b/akka-actor/src/main/scala/akka/event/EventHandler.scala
@@ -44,6 +44,11 @@ import akka.AkkaException
* EventHandler.error(exception, this, message)
*
*
+ * Shut down the EventHandler:
+ *
+ * EventHandler.shutdown()
+ *
+ *
* @author Jonas Bonér
*/
object EventHandler extends ListenerManagement {
@@ -85,7 +90,7 @@ object EventHandler extends ListenerManagement {
lazy val EventHandlerDispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher(ID).build
- val level: Int = config.getString("akka.event-handler-level", "DEBUG") match {
+ val level: Int = config.getString("akka.event-handler-level", "INFO") match {
case "ERROR" => ErrorLevel
case "WARNING" => WarningLevel
case "INFO" => InfoLevel
@@ -94,6 +99,14 @@ object EventHandler extends ListenerManagement {
"Configuration option 'akka.event-handler-level' is invalid [" + unknown + "]")
}
+ /**
+ * Shuts down all event handler listeners including the event handle dispatcher.
+ */
+ def shutdown() {
+ foreachListener(_.stop())
+ EventHandlerDispatcher.shutdown()
+ }
+
def notify(event: Any) {
if (event.isInstanceOf[Event]) {
if (level >= event.asInstanceOf[Event].level) notifyListeners(event)
@@ -207,14 +220,15 @@ object EventHandler extends ListenerManagement {
}
defaultListeners foreach { listenerName =>
try {
- ReflectiveAccess.getClassFor[Actor](listenerName) map { clazz =>
- addListener(Actor.actorOf(clazz).start())
+ ReflectiveAccess.getClassFor[Actor](listenerName) match {
+ case r: Right[_, Class[Actor]] => addListener(Actor.actorOf(r.b).start())
+ case l: Left[Exception,_] => throw l.a
}
} catch {
case e: Exception =>
throw new ConfigurationException(
"Event Handler specified in config can't be loaded [" + listenerName +
- "] due to [" + e.toString + "]")
+ "] due to [" + e.toString + "]", e)
}
}
}
diff --git a/akka-actor/src/main/scala/akka/remoteinterface/RemoteInterface.scala b/akka-actor/src/main/scala/akka/remoteinterface/RemoteInterface.scala
index 081b622f39..0409ae9d6c 100644
--- a/akka-actor/src/main/scala/akka/remoteinterface/RemoteInterface.scala
+++ b/akka-actor/src/main/scala/akka/remoteinterface/RemoteInterface.scala
@@ -116,7 +116,7 @@ case class RemoteServerWriteFailed(
class RemoteClientException private[akka] (
message: String,
@BeanProperty val client: RemoteClientModule,
- val remoteAddress: InetSocketAddress) extends AkkaException(message)
+ val remoteAddress: InetSocketAddress, cause: Throwable = null) extends AkkaException(message, cause)
/**
* Thrown when the remote server actor dispatching fails for some reason.
@@ -143,11 +143,11 @@ abstract class RemoteSupport extends ListenerManagement with RemoteServerModule
handler
}
- def shutdown {
+ def shutdown() {
eventHandler.stop()
removeListener(eventHandler)
- this.shutdownClientModule
- this.shutdownServerModule
+ this.shutdownClientModule()
+ this.shutdownServerModule()
clear
}
@@ -189,13 +189,14 @@ abstract class RemoteSupport extends ListenerManagement with RemoteServerModule
def actorOf(clazz: Class[_ <: Actor], host: String, port: Int): ActorRef = {
import ReflectiveAccess.{ createInstance, noParams, noArgs }
clientManagedActorOf(() =>
- createInstance[Actor](clazz.asInstanceOf[Class[_]], noParams, noArgs).getOrElse(
- throw new ActorInitializationException(
- "Could not instantiate Actor" +
- "\nMake sure Actor is NOT defined inside a class/trait," +
- "\nif so put it outside the class/trait, f.e. in a companion object," +
- "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.")),
- host, port)
+ createInstance[Actor](clazz.asInstanceOf[Class[_]], noParams, noArgs) match {
+ case r: Right[_, Actor] => r.b
+ case l: Left[Exception, _] => throw new ActorInitializationException(
+ "Could not instantiate Actor" +
+ "\nMake sure Actor is NOT defined inside a class/trait," +
+ "\nif so put it outside the class/trait, f.e. in a companion object," +
+ "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.", l.a)
+ }, host, port)
}
/**
@@ -217,13 +218,14 @@ abstract class RemoteSupport extends ListenerManagement with RemoteServerModule
def actorOf[T <: Actor : Manifest](host: String, port: Int): ActorRef = {
import ReflectiveAccess.{ createInstance, noParams, noArgs }
clientManagedActorOf(() =>
- createInstance[Actor](manifest[T].erasure.asInstanceOf[Class[_]], noParams, noArgs).getOrElse(
- throw new ActorInitializationException(
- "Could not instantiate Actor" +
- "\nMake sure Actor is NOT defined inside a class/trait," +
- "\nif so put it outside the class/trait, f.e. in a companion object," +
- "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.")),
- host, port)
+ createInstance[Actor](manifest[T].erasure.asInstanceOf[Class[_]], noParams, noArgs) match {
+ case r: Right[_, Actor] => r.b
+ case l: Left[Exception, _] => throw new ActorInitializationException(
+ "Could not instantiate Actor" +
+ "\nMake sure Actor is NOT defined inside a class/trait," +
+ "\nif so put it outside the class/trait, f.e. in a companion object," +
+ "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.", l.a)
+ }, host, port)
}
protected override def manageLifeCycleOfListeners = false
@@ -354,7 +356,8 @@ trait RemoteServerModule extends RemoteModule {
def registerByUuid(actorRef: ActorRef): Unit
/**
- * Register Remote Actor by a specific 'id' passed as argument.
+ * Register Remote Actor by a specific 'id' passed as argument. The actor is registered by UUID rather than ID
+ * when prefixing the handle with the “uuid:” protocol.
*
* NOTE: If you use this method to register your remote actor then you must unregister the actor by this ID yourself.
*/
diff --git a/akka-actor/src/main/scala/akka/routing/Pool.scala b/akka-actor/src/main/scala/akka/routing/Pool.scala
index 6ab6aa0c4d..5a906df851 100644
--- a/akka-actor/src/main/scala/akka/routing/Pool.scala
+++ b/akka-actor/src/main/scala/akka/routing/Pool.scala
@@ -54,7 +54,7 @@ trait DefaultActorPool extends ActorPool { this: Actor =>
private var _lastCapacityChange = 0
private var _lastSelectorCount = 0
- override def postStop = _delegates foreach {
+ override def postStop() = _delegates foreach {
delegate => try {
delegate ! PoisonPill
} catch { case e: Exception => } //Ignore any exceptions here
diff --git a/akka-actor/src/main/scala/akka/util/AkkaLoader.scala b/akka-actor/src/main/scala/akka/util/AkkaLoader.scala
index b7f113313d..2a2ee13db7 100644
--- a/akka-actor/src/main/scala/akka/util/AkkaLoader.scala
+++ b/akka-actor/src/main/scala/akka/util/AkkaLoader.scala
@@ -21,7 +21,7 @@ class AkkaLoader {
* Boot initializes the specified bundles
*/
def boot(withBanner: Boolean, b : Bootable): Unit = hasBooted switchOn {
- if (withBanner) printBanner
+ if (withBanner) printBanner()
println("Starting Akka...")
b.onLoad
Thread.currentThread.setContextClassLoader(getClass.getClassLoader)
@@ -32,15 +32,17 @@ class AkkaLoader {
/*
* Shutdown, well, shuts down the bundles used in boot
*/
- def shutdown: Unit = hasBooted switchOff {
- println("Shutting down Akka...")
- _bundles.foreach(_.onUnload)
- _bundles = None
- Actor.shutdownHook.run
- println("Akka succesfully shut down")
+ def shutdown() {
+ hasBooted switchOff {
+ println("Shutting down Akka...")
+ _bundles.foreach(_.onUnload)
+ _bundles = None
+ Actor.shutdownHook.run
+ println("Akka succesfully shut down")
+ }
}
- private def printBanner = {
+ private def printBanner() {
println("==================================================")
println(" t")
println(" t t t")
diff --git a/akka-actor/src/main/scala/akka/util/Bootable.scala b/akka-actor/src/main/scala/akka/util/Bootable.scala
index bea62e5ac7..d07643e1ac 100644
--- a/akka-actor/src/main/scala/akka/util/Bootable.scala
+++ b/akka-actor/src/main/scala/akka/util/Bootable.scala
@@ -5,6 +5,6 @@
package akka.util
trait Bootable {
- def onLoad {}
- def onUnload {}
+ def onLoad() {}
+ def onUnload() {}
}
diff --git a/akka-actor/src/main/scala/akka/util/Duration.scala b/akka-actor/src/main/scala/akka/util/Duration.scala
index 933e3cd9a9..4e105c198f 100644
--- a/akka-actor/src/main/scala/akka/util/Duration.scala
+++ b/akka-actor/src/main/scala/akka/util/Duration.scala
@@ -96,15 +96,32 @@ object Duration {
case "ns" | "nano" | "nanos" | "nanosecond" | "nanoseconds" => NANOSECONDS
}
+ val Zero : Duration = new FiniteDuration(0, NANOSECONDS)
+
trait Infinite {
this : Duration =>
override def equals(other : Any) = false
- def +(other : Duration) : Duration = this
- def -(other : Duration) : Duration = this
- def *(other : Double) : Duration = this
- def /(other : Double) : Duration = this
+ def +(other : Duration) : Duration =
+ other match {
+ case _ : this.type => this
+ case _ : Infinite => throw new IllegalArgumentException("illegal addition of infinities")
+ case _ => this
+ }
+ def -(other : Duration) : Duration =
+ other match {
+ case _ : this.type => throw new IllegalArgumentException("illegal subtraction of infinities")
+ case _ => this
+ }
+ def *(factor : Double) : Duration = this
+ def /(factor : Double) : Duration = this
+ def /(other : Duration) : Double =
+ other match {
+ case _ : Infinite => throw new IllegalArgumentException("illegal division of infinities")
+ // maybe questionable but pragmatic: Inf / 0 => Inf
+ case x => Double.PositiveInfinity * (if ((this > Zero) ^ (other >= Zero)) -1 else 1)
+ }
def finite_? = false
@@ -126,7 +143,7 @@ object Duration {
* Infinite duration: greater than any other and not equal to any other,
* including itself.
*/
- object Inf extends Duration with Infinite {
+ val Inf : Duration = new Duration with Infinite {
override def toString = "Duration.Inf"
def >(other : Duration) = true
def >=(other : Duration) = true
@@ -139,7 +156,7 @@ object Duration {
* Infinite negative duration: lesser than any other and not equal to any other,
* including itself.
*/
- object MinusInf extends Duration with Infinite {
+ val MinusInf : Duration = new Duration with Infinite {
override def toString = "Duration.MinusInf"
def >(other : Duration) = false
def >=(other : Duration) = false
@@ -148,6 +165,11 @@ object Duration {
def unary_- : Duration = Inf
}
+ // Java Factories
+ def create(length : Long, unit : TimeUnit) : Duration = apply(length, unit)
+ def create(length : Double, unit : TimeUnit) : Duration = apply(length, unit)
+ def create(length : Long, unit : String) : Duration = apply(length, unit)
+ def parse(s : String) : Duration = unapply(s).get
}
/**
@@ -195,7 +217,7 @@ object Duration {
* val d3 = d2 + 1.millisecond
*
*/
-trait Duration {
+abstract class Duration {
def length : Long
def unit : TimeUnit
def toNanos : Long
@@ -215,8 +237,22 @@ trait Duration {
def -(other : Duration) : Duration
def *(factor : Double) : Duration
def /(factor : Double) : Duration
+ def /(other : Duration) : Double
def unary_- : Duration
def finite_? : Boolean
+
+ // 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_?
}
class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
@@ -306,6 +342,8 @@ class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
def /(factor : Double) = fromNanos(long2double(toNanos) / factor)
+ def /(other : Duration) = if (other.finite_?) long2double(toNanos) / other.toNanos else 0
+
def unary_- = Duration(-length, unit)
def finite_? = true
diff --git a/akka-actor/src/main/scala/akka/util/ListenerManagement.scala b/akka-actor/src/main/scala/akka/util/ListenerManagement.scala
index efeb482377..ede46fc80a 100644
--- a/akka-actor/src/main/scala/akka/util/ListenerManagement.scala
+++ b/akka-actor/src/main/scala/akka/util/ListenerManagement.scala
@@ -45,7 +45,7 @@ trait ListenerManagement {
def hasListeners: Boolean = !listeners.isEmpty
/**
- * Checks if a specfic listener is registered. ActorInitializationException leads to removal of listener if that
+ * Checks if a specific listener is registered. ActorInitializationException leads to removal of listener if that
* one isShutdown.
*/
def hasListener(listener: ActorRef): Boolean = listeners.contains(listener)
diff --git a/akka-actor/src/main/scala/akka/util/ReflectiveAccess.scala b/akka-actor/src/main/scala/akka/util/ReflectiveAccess.scala
index f4ceba6ebe..14b46ceae5 100644
--- a/akka-actor/src/main/scala/akka/util/ReflectiveAccess.scala
+++ b/akka-actor/src/main/scala/akka/util/ReflectiveAccess.scala
@@ -42,12 +42,16 @@ object ReflectiveAccess {
lazy val isEnabled = remoteSupportClass.isDefined
def ensureEnabled = if (!isEnabled) {
- val e = new ModuleNotAvailableException(
- "Can't load the remoting module, make sure that akka-remote.jar is on the classpath")
+ val e = new ModuleNotAvailableException("Can't load the remoting module, make sure that akka-remote.jar is on the classpath")
EventHandler.debug(this, e.toString)
throw e
}
- val remoteSupportClass: Option[Class[_ <: RemoteSupport]] = getClassFor(TRANSPORT)
+ val remoteSupportClass = getClassFor[RemoteSupport](TRANSPORT) match {
+ case Right(value) => Some(value)
+ case Left(exception) =>
+ EventHandler.debug(this, exception.toString)
+ None
+ }
protected[akka] val defaultRemoteSupport: Option[() => RemoteSupport] =
remoteSupportClass map { remoteClass =>
@@ -55,9 +59,11 @@ object ReflectiveAccess {
remoteClass,
Array[Class[_]](),
Array[AnyRef]()
- ) getOrElse {
+ ) match {
+ case Right(value) => value
+ case Left(exception) =>
val e = new ModuleNotAvailableException(
- "Can't instantiate [%s] - make sure that akka-remote.jar is on the classpath".format(remoteClass.getName))
+ "Can't instantiate [%s] - make sure that akka-remote.jar is on the classpath".format(remoteClass.getName), exception)
EventHandler.debug(this, e.toString)
throw e
}
@@ -85,7 +91,12 @@ object ReflectiveAccess {
"Can't load the typed actor module, make sure that akka-typed-actor.jar is on the classpath")
val typedActorObjectInstance: Option[TypedActorObject] =
- getObjectFor("akka.actor.TypedActor$")
+ getObjectFor[TypedActorObject]("akka.actor.TypedActor$") match {
+ case Right(value) => Some(value)
+ case Left(exception)=>
+ EventHandler.debug(this, exception.toString)
+ None
+ }
def resolveFutureIfMessageIsJoinPoint(message: Any, future: Future[_]): Boolean = {
ensureEnabled
@@ -111,10 +122,20 @@ object ReflectiveAccess {
lazy val isEnabled = clusterObjectInstance.isDefined
val clusterObjectInstance: Option[AnyRef] =
- getObjectFor("akka.cloud.cluster.Cluster$")
+ getObjectFor[AnyRef]("akka.cloud.cluster.Cluster$") match {
+ case Right(value) => Some(value)
+ case Left(exception) =>
+ EventHandler.debug(this, exception.toString)
+ None
+ }
val serializerClass: Option[Class[_]] =
- getClassFor("akka.serialization.Serializer")
+ getClassFor("akka.serialization.Serializer") match {
+ case Right(value) => Some(value)
+ case Left(exception) =>
+ EventHandler.debug(this, exception.toString)
+ None
+ }
def ensureEnabled = if (!isEnabled) throw new ModuleNotAvailableException(
"Feature is only available in Akka Cloud")
@@ -125,99 +146,88 @@ object ReflectiveAccess {
def createInstance[T](clazz: Class[_],
params: Array[Class[_]],
- args: Array[AnyRef]): Option[T] = try {
+ args: Array[AnyRef]): Either[Exception,T] = try {
assert(clazz ne null)
assert(params ne null)
assert(args ne null)
val ctor = clazz.getDeclaredConstructor(params: _*)
ctor.setAccessible(true)
- Some(ctor.newInstance(args: _*).asInstanceOf[T])
+ Right(ctor.newInstance(args: _*).asInstanceOf[T])
} catch {
- case e: Exception =>
- EventHandler.debug(this, e.toString)
- None
+ case e: Exception => Left(e)
}
def createInstance[T](fqn: String,
params: Array[Class[_]],
args: Array[AnyRef],
- classloader: ClassLoader = loader): Option[T] = try {
+ classloader: ClassLoader = loader): Either[Exception,T] = try {
assert(params ne null)
assert(args ne null)
getClassFor(fqn) match {
- case Some(clazz) =>
- val ctor = clazz.getDeclaredConstructor(params: _*)
+ case Right(value) =>
+ val ctor = value.getDeclaredConstructor(params: _*)
ctor.setAccessible(true)
- Some(ctor.newInstance(args: _*).asInstanceOf[T])
- case None => None
+ Right(ctor.newInstance(args: _*).asInstanceOf[T])
+ case Left(exception) => Left(exception) //We could just cast this to Either[Exception, T] but it's ugly
}
} catch {
case e: Exception =>
- EventHandler.debug(this, e.toString)
- None
+ Left(e)
}
- def getObjectFor[T](fqn: String, classloader: ClassLoader = loader): Option[T] = try {//Obtains a reference to $MODULE$
+ //Obtains a reference to fqn.MODULE$
+ def getObjectFor[T](fqn: String, classloader: ClassLoader = loader): Either[Exception,T] = try {
getClassFor(fqn) match {
- case Some(clazz) =>
- val instance = clazz.getDeclaredField("MODULE$")
+ case Right(value) =>
+ val instance = value.getDeclaredField("MODULE$")
instance.setAccessible(true)
- Option(instance.get(null).asInstanceOf[T])
- case None => None
+ val obj = instance.get(null)
+ if (obj eq null) Left(new NullPointerException) else Right(obj.asInstanceOf[T])
+ case Left(exception) => Left(exception) //We could just cast this to Either[Exception, T] but it's ugly
}
} catch {
- case e: ExceptionInInitializerError =>
- EventHandler.debug(this, e.toString)
- throw e
+ case e: Exception =>
+ Left(e)
}
- def getClassFor[T](fqn: String, classloader: ClassLoader = loader): Option[Class[T]] = {
+ def getClassFor[T](fqn: String, classloader: ClassLoader = loader): Either[Exception,Class[T]] = try {
assert(fqn ne null)
// First, use the specified CL
val first = try {
- Option(classloader.loadClass(fqn).asInstanceOf[Class[T]])
+ Right(classloader.loadClass(fqn).asInstanceOf[Class[T]])
} catch {
- case c: ClassNotFoundException =>
- EventHandler.debug(this, c.toString)
- None
+ case c: ClassNotFoundException => Left(c)
}
- if (first.isDefined) first
+ if (first.isRight) first
else {
// Second option is to use the ContextClassLoader
val second = try {
- Option(Thread.currentThread.getContextClassLoader.loadClass(fqn).asInstanceOf[Class[T]])
+ Right(Thread.currentThread.getContextClassLoader.loadClass(fqn).asInstanceOf[Class[T]])
} catch {
- case c: ClassNotFoundException =>
- EventHandler.debug(this, c.toString)
- None
+ case c: ClassNotFoundException => Left(c)
}
- if (second.isDefined) second
+ if (second.isRight) second
else {
val third = try {
- // Don't try to use "loader" if we got the default "classloader" parameter
- if (classloader ne loader) Option(loader.loadClass(fqn).asInstanceOf[Class[T]])
- else None
+ if (classloader ne loader) Right(loader.loadClass(fqn).asInstanceOf[Class[T]]) else Left(null) //Horrid
} catch {
- case c: ClassNotFoundException =>
- EventHandler.debug(this, c.toString)
- None
+ case c: ClassNotFoundException => Left(c)
}
- if (third.isDefined) third
+ if (third.isRight) third
else {
- // Last option is Class.forName
try {
- Option(Class.forName(fqn).asInstanceOf[Class[T]])
+ Right(Class.forName(fqn).asInstanceOf[Class[T]]) // Last option is Class.forName
} catch {
- case c: ClassNotFoundException =>
- EventHandler.debug(this, c.toString)
- None
+ case c: ClassNotFoundException => Left(c)
}
}
}
}
+ } catch {
+ case e: Exception => Left(e)
}
}
diff --git a/akka-docs/conf.py b/akka-docs/conf.py
index 209f747afc..712a3d10c8 100644
--- a/akka-docs/conf.py
+++ b/akka-docs/conf.py
@@ -13,7 +13,7 @@ extensions = ['sphinx.ext.todo', 'includecode']
templates_path = ['_templates']
source_suffix = '.rst'
master_doc = 'index'
-exclude_patterns = ['_build', 'pending']
+exclude_patterns = ['_build', 'pending', 'disabled']
project = u'Akka'
copyright = u'2009-2011, Scalable Solutions AB'
diff --git a/akka-docs/intro/examples/Pi.scala b/akka-docs/disabled/examples/Pi.scala
similarity index 96%
rename from akka-docs/intro/examples/Pi.scala
rename to akka-docs/disabled/examples/Pi.scala
index 6bf1dea903..41f8e88b9f 100644
--- a/akka-docs/intro/examples/Pi.scala
+++ b/akka-docs/disabled/examples/Pi.scala
@@ -36,7 +36,7 @@ object Pi extends App {
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
var acc = 0.0
for (i <- start until (start + nrOfElements))
- acc += 4 * math.pow(-1, i) / (2 * i + 1)
+ acc += 4.0 * math.pow(-1, i) / (2 * i + 1)
acc
}
//#calculate-pi
@@ -91,11 +91,11 @@ object Pi extends App {
}
//#master-receive
- override def preStart {
+ override def preStart() {
start = now
}
- override def postStop {
+ override def postStop() {
// tell the world that the calculation is complete
println(
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
diff --git a/akka-docs/intro/getting-started-first.rst b/akka-docs/disabled/getting-started-first.rst
similarity index 98%
rename from akka-docs/intro/getting-started-first.rst
rename to akka-docs/disabled/getting-started-first.rst
index aaa466c1dc..63683a8c17 100644
--- a/akka-docs/intro/getting-started-first.rst
+++ b/akka-docs/disabled/getting-started-first.rst
@@ -19,14 +19,17 @@ We will be using an algorithm that is called "embarrassingly parallel" which jus
Here is the formula for the algorithm we will use:
-.. image:: pi-formula.png
+.. image:: ../images/pi-formula.png
In this particular algorithm the master splits the series into chunks which are sent out to each worker actor to be processed. When each worker has processed its chunk it sends a result back to the master which aggregates the total result.
Tutorial source code
--------------------
-If you want don't want to type in the code and/or set up an SBT project then you can check out the full tutorial from the Akka GitHub repository. It is in the ``akka-tutorials/akka-tutorial-first`` module. You can also browse it online `here `_, with the actual source code `here `_.
+If you want don't want to type in the code and/or set up an SBT project then you can check out the full tutorial from the Akka GitHub repository. It is in the ``akka-tutorials/akka-tutorial-first`` module. You can also browse it online `here`__, with the actual source code `here`__.
+
+__ https://github.com/jboner/akka/tree/master/akka-tutorials/akka-tutorial-first
+__ https://github.com/jboner/akka/blob/master/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala
Prerequisites
-------------
@@ -266,8 +269,6 @@ But before we package it up and run it, let's take a look at the full code now,
.. includecode:: examples/Pi.scala
-
-
Run it as a command line application
------------------------------------
diff --git a/akka-docs/general/building-akka.rst b/akka-docs/general/building-akka.rst
new file mode 100644
index 0000000000..3ed3b151bc
--- /dev/null
+++ b/akka-docs/general/building-akka.rst
@@ -0,0 +1,173 @@
+
+.. highlightlang:: none
+
+.. _building-akka:
+
+###############
+ Building Akka
+###############
+
+This page describes how to build and run Akka from the latest source code.
+
+.. contents:: :local:
+
+
+Get the source code
+===================
+
+Akka uses `Git`_ and is hosted at `Github`_.
+
+.. _Git: http://git-scm.com
+.. _Github: http://github.com
+
+You first need Git installed on your machine. You can then clone the source
+repositories:
+
+- Akka repository from http://github.com/jboner/akka
+- Akka Modules repository from http://github.com/jboner/akka-modules
+
+For example::
+
+ git clone git://github.com/jboner/akka.git
+ git clone git://github.com/jboner/akka-modules.git
+
+If you have already cloned the repositories previously then you can update the
+code with ``git pull``::
+
+ git pull origin master
+
+
+SBT - Simple Build Tool
+=======================
+
+Akka is using the excellent `SBT`_ build system. So the first thing you have to
+do is to download and install SBT. You can read more about how to do that in the
+`SBT setup`_ documentation.
+
+.. _SBT: http://code.google.com/p/simple-build-tool
+.. _SBT setup: http://code.google.com/p/simple-build-tool/wiki/Setup
+
+The SBT commands that you'll need to build Akka are all included below. If you
+want to find out more about SBT and using it for your own projects do read the
+`SBT documentation`_.
+
+.. _SBT documentation: http://code.google.com/p/simple-build-tool/wiki/RunningSbt
+
+The Akka SBT build file is ``project/build/AkkaProject.scala`` with some
+properties defined in ``project/build.properties``.
+
+
+Building Akka
+=============
+
+First make sure that you are in the akka code directory::
+
+ cd akka
+
+
+Fetching dependencies
+---------------------
+
+SBT does not fetch dependencies automatically. You need to manually do this with
+the ``update`` command::
+
+ sbt update
+
+Once finished, all the dependencies for Akka will be in the ``lib_managed``
+directory under each module: akka-actor, akka-stm, and so on.
+
+*Note: you only need to run update the first time you are building the code,
+or when the dependencies have changed.*
+
+
+Building
+--------
+
+To compile all the Akka core modules use the ``compile`` command::
+
+ sbt compile
+
+You can run all tests with the ``test`` command::
+
+ sbt test
+
+If compiling and testing are successful then you have everything working for the
+latest Akka development version.
+
+
+Publish to local Ivy repository
+-------------------------------
+
+If you want to deploy the artifacts to your local Ivy repository (for example,
+to use from an SBT project) use the ``publish-local`` command::
+
+ sbt publish-local
+
+
+Publish to local Maven repository
+---------------------------------
+
+If you want to deploy the artifacts to your local Maven repository use::
+
+ sbt publish-local publish
+
+
+SBT interactive mode
+--------------------
+
+Note that in the examples above we are calling ``sbt compile`` and ``sbt test``
+and so on. SBT also has an interactive mode. If you just run ``sbt`` you enter
+the interactive SBT prompt and can enter the commands directly. This saves
+starting up a new JVM instance for each command and can be much faster and more
+convenient.
+
+For example, building Akka as above is more commonly done like this::
+
+ % sbt
+ [info] Building project akka 1.1-SNAPSHOT against Scala 2.9.0.RC1
+ [info] using AkkaParentProject with sbt 0.7.6.RC0 and Scala 2.7.7
+ > update
+ [info]
+ [info] == akka-actor / update ==
+ ...
+ [success] Successful.
+ [info]
+ [info] Total time ...
+ > compile
+ ...
+ > test
+ ...
+
+
+SBT batch mode
+--------------
+
+It's also possible to combine commands in a single call. For example, updating,
+testing, and publishing Akka to the local Ivy repository can be done with::
+
+ sbt update test publish-local
+
+
+Building Akka Modules
+=====================
+
+See the Akka Modules documentation.
+
+
+Dependencies
+============
+
+If you are managing dependencies by hand you can find the dependencies for each
+module by looking in the ``lib_managed`` directories. For example, this will
+list all compile dependencies (providing you have the source code and have run
+``sbt update``)::
+
+ cd akka
+ ls -1 */lib_managed/compile
+
+You can also look at the Ivy dependency resolution information that is created
+on ``sbt update`` and found in ``~/.ivy2/cache``. For example, the
+``.ivy2/cache/se.scalablesolutions.akka-akka-remote-compile.xml`` file contains
+the resolution information for the akka-remote module compile dependencies. If
+you open this file in a web browser you will get an easy to navigate view of
+dependencies.
diff --git a/akka-docs/intro/configuration.rst b/akka-docs/general/configuration.rst
similarity index 100%
rename from akka-docs/intro/configuration.rst
rename to akka-docs/general/configuration.rst
diff --git a/akka-docs/pending/event-handler.rst b/akka-docs/general/event-handler.rst
similarity index 91%
rename from akka-docs/pending/event-handler.rst
rename to akka-docs/general/event-handler.rst
index 18eefefb0a..e43bb20eb0 100644
--- a/akka-docs/pending/event-handler.rst
+++ b/akka-docs/general/event-handler.rst
@@ -12,7 +12,8 @@ You can configure which event handlers should be registered at boot time. That i
.. code-block:: ruby
akka {
- event-handlers = ["akka.event.EventHandler$DefaultListener"] # event handlers to register at boot time (EventHandler$DefaultListener logs to STDOUT)
+ # event handlers to register at boot time (EventHandler$DefaultListener logs to STDOUT)
+ event-handlers = ["akka.event.EventHandler$DefaultListener"]
event-handler-level = "DEBUG" # Options: ERROR, WARNING, INFO, DEBUG
}
@@ -88,9 +89,10 @@ The methods take a call-by-name parameter for the message to avoid object alloca
From Java you need to nest the call in an if statement to achieve the same thing.
-``_
-if (EventHandler.isDebugEnabled()) {
- EventHandler.debug(this, String.format("Processing took %s ms", duration));
-}
+.. code-block:: java
+
+ if (EventHandler.isDebugEnabled()) {
+ EventHandler.debug(this, String.format("Processing took %s ms", duration));
+ }
+
-``_
diff --git a/akka-docs/general/index.rst b/akka-docs/general/index.rst
index 1d716ed63a..367e45b9d5 100644
--- a/akka-docs/general/index.rst
+++ b/akka-docs/general/index.rst
@@ -2,10 +2,10 @@ General
=======
.. toctree::
- :maxdepth: 1
+ :maxdepth: 2
- migration-guide-0.7.x-0.8.x
- migration-guide-0.8.x-0.9.x
- migration-guide-0.9.x-0.10.x
- migration-guide-0.10.x-1.0.x
- migration-guide-1.0.x-1.1.x
+ migration-guides
+ building-akka
+ configuration
+ event-handler
+ util
diff --git a/akka-docs/general/migration-guide-0.9.x-0.10.x.rst b/akka-docs/general/migration-guide-0.9.x-0.10.x.rst
index 85c2b54e93..78b2ddc303 100644
--- a/akka-docs/general/migration-guide-0.9.x-0.10.x.rst
+++ b/akka-docs/general/migration-guide-0.9.x-0.10.x.rst
@@ -8,8 +8,10 @@ The following list summarizes the breaking changes since Akka 0.9.1.
* CamelService moved from package se.scalablesolutions.akka.camel.service one level up to se.scalablesolutions.akka.camel.
* CamelService.newInstance removed. For starting and stopping a CamelService, applications should use
-** CamelServiceManager.startCamelService and
-** CamelServiceManager.stopCamelService.
+
+ * CamelServiceManager.startCamelService and
+ * CamelServiceManager.stopCamelService.
+
* Existing def receive = produce method definitions from Producer implementations must be removed (resolves compile error: method receive needs override modifier).
* The Producer.async method and the related Sync trait have been removed. This is now fully covered by Camel's `asynchronous routing engine `_.
* @consume annotation can not placed any longer on actors (i.e. on type-level), only on typed actor methods. Consumer actors must mixin the Consumer trait.
diff --git a/akka-docs/general/migration-guide-1.0.x-1.1.x.rst b/akka-docs/general/migration-guide-1.0.x-1.1.x.rst
index c473c44129..e9b27c5032 100644
--- a/akka-docs/general/migration-guide-1.0.x-1.1.x.rst
+++ b/akka-docs/general/migration-guide-1.0.x-1.1.x.rst
@@ -15,11 +15,12 @@ Akka Actor
----------
# is now dependency free, with the exception of the dependency on the ``scala-library.jar``
-# does not bundle any logging anymore, but you can subscribe to events within Akka by registering an event handler on akka.aevent.EventHandler or by specifying the ``FQN`` of an Actor in the akka.conf under akka.event-handlers; there is an ``akka-slf4j`` module which still provides the Logging trait and a default ``SLF4J`` logger adapter.
+# does not bundle any logging anymore, but you can subscribe to events within Akka by registering an event handler on akka.event.EventHandler or by specifying the ``FQN`` of an Actor in the akka.conf under akka.event-handlers; there is an ``akka-slf4j`` module which still provides the Logging trait and a default ``SLF4J`` logger adapter.
Don't forget to add a SLF4J backend though, we recommend:
.. code-block:: scala
- lazy val logback = "ch.qos.logback" % "logback-classic" % "0.9.28"
+
+ lazy val logback = "ch.qos.logback" % "logback-classic" % "0.9.28" % "runtime"
# If you used HawtDispatcher and want to continue using it, you need to include akka-dispatcher-extras.jar from Akka Modules, in your akka.conf you need to specify: ``akka.dispatch.HawtDispatcherConfigurator`` instead of ``HawtDispatcher``
# FSM: the onTransition method changed from Function1 to PartialFunction; there is an implicit conversion for the precise types in place, but it may be necessary to add an underscore if you are passing an eta-expansion (using a method as function value).
@@ -37,4 +38,4 @@ Akka Remote
Akka Testkit
------------
-The TestKit moved into the akka-testkit subproject and correspondingly into the ``akka.testkit` package.
+The TestKit moved into the akka-testkit subproject and correspondingly into the ``akka.testkit`` package.
diff --git a/akka-docs/general/migration-guides.rst b/akka-docs/general/migration-guides.rst
new file mode 100644
index 0000000000..ed9c1de270
--- /dev/null
+++ b/akka-docs/general/migration-guides.rst
@@ -0,0 +1,10 @@
+Migration Guides
+================
+
+.. toctree::
+ :maxdepth: 1
+
+ migration-guide-0.7.x-0.8.x
+ migration-guide-0.8.x-0.9.x
+ migration-guide-0.9.x-0.10.x
+ migration-guide-1.0.x-1.1.x
diff --git a/akka-docs/general/util.rst b/akka-docs/general/util.rst
new file mode 100644
index 0000000000..bb0f61e778
--- /dev/null
+++ b/akka-docs/general/util.rst
@@ -0,0 +1,49 @@
+#########
+Utilities
+#########
+
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
+This section of the manual describes miscellaneous utilities which are provided
+by Akka and used in multiple places.
+
+.. _Duration:
+
+Duration
+========
+
+Durations are used throughout the Akka library, wherefore this concept is
+represented by a special data type, :class:`Duration`. Values of this type may
+represent infinite (:obj:`Duration.Inf`, :obj:`Duration.MinusInf`) or finite
+durations, where the latter are constructable using a mini-DSL:
+
+.. code-block:: scala
+
+ import akka.util.duration._ // notice the small d
+
+ val fivesec = 5.seconds
+ val threemillis = 3.millis
+ val diff = fivesec - threemillis
+ assert (diff < fivesec)
+
+.. note::
+
+ You may leave out the dot if the expression is clearly delimited (e.g.
+ within parentheses or in an argument list), but it is recommended to use it
+ if the time unit is the last token on a line, otherwise semi-colon inference
+ might go wrong, depending on what starts the next line.
+
+Java provides less syntactic sugar, so you have to spell out the operations as
+method calls instead:
+
+.. code-block:: java
+
+ final Duration fivesec = Duration.create(5, "seconds");
+ final Duration threemillis = Duration.parse("3 millis");
+ final Duration diff = fivesec.minus(threemillis);
+ assert (diff.lt(fivesec));
+ assert (Duration.Zero().lt(Duration.Inf()));
+
+
diff --git a/akka-docs/intro/build-path.png b/akka-docs/images/build-path.png
similarity index 100%
rename from akka-docs/intro/build-path.png
rename to akka-docs/images/build-path.png
diff --git a/akka-docs/images/clojure-trees.png b/akka-docs/images/clojure-trees.png
new file mode 100644
index 0000000000..60127d52b2
Binary files /dev/null and b/akka-docs/images/clojure-trees.png differ
diff --git a/akka-docs/intro/diagnostics-window.png b/akka-docs/images/diagnostics-window.png
similarity index 100%
rename from akka-docs/intro/diagnostics-window.png
rename to akka-docs/images/diagnostics-window.png
diff --git a/akka-docs/intro/example-code.png b/akka-docs/images/example-code.png
similarity index 100%
rename from akka-docs/intro/example-code.png
rename to akka-docs/images/example-code.png
diff --git a/akka-docs/intro/import-project.png b/akka-docs/images/import-project.png
similarity index 100%
rename from akka-docs/intro/import-project.png
rename to akka-docs/images/import-project.png
diff --git a/akka-docs/intro/install-beta2-updatesite.png b/akka-docs/images/install-beta2-updatesite.png
similarity index 100%
rename from akka-docs/intro/install-beta2-updatesite.png
rename to akka-docs/images/install-beta2-updatesite.png
diff --git a/akka-docs/intro/pi-formula.png b/akka-docs/images/pi-formula.png
similarity index 100%
rename from akka-docs/intro/pi-formula.png
rename to akka-docs/images/pi-formula.png
diff --git a/akka-docs/intro/quickfix.png b/akka-docs/images/quickfix.png
similarity index 100%
rename from akka-docs/intro/quickfix.png
rename to akka-docs/images/quickfix.png
diff --git a/akka-docs/intro/run-config.png b/akka-docs/images/run-config.png
similarity index 100%
rename from akka-docs/intro/run-config.png
rename to akka-docs/images/run-config.png
diff --git a/akka-docs/index.rst b/akka-docs/index.rst
index fbb2506fab..11bfef862a 100644
--- a/akka-docs/index.rst
+++ b/akka-docs/index.rst
@@ -7,6 +7,7 @@ Contents
intro/index
general/index
scala/index
+ java/index
dev/index
Links
diff --git a/akka-docs/intro/building-akka.rst b/akka-docs/intro/building-akka.rst
deleted file mode 100644
index 3d4f4ca1a0..0000000000
--- a/akka-docs/intro/building-akka.rst
+++ /dev/null
@@ -1,340 +0,0 @@
-Building Akka
-=============
-
-This page describes how to build and run Akka from the latest source code.
-
-.. contents:: :local:
-
-
-Get the source code
--------------------
-
-Akka uses `Git `_ and is hosted at `Github
-`_.
-
-You first need Git installed on your machine. You can then clone the source
-repositories:
-
-- Akka repository from ``_
-- Akka Modules repository from ``_
-
-For example::
-
- git clone git://github.com/jboner/akka.git
- git clone git://github.com/jboner/akka-modules.git
-
-If you have already cloned the repositories previously then you can update the
-code with ``git pull``::
-
- git pull origin master
-
-
-SBT - Simple Build Tool
------------------------
-
-Akka is using the excellent `SBT `_
-build system. So the first thing you have to do is to download and install
-SBT. You can read more about how to do that `here
-`_ .
-
-The SBT commands that you'll need to build Akka are all included below. If you
-want to find out more about SBT and using it for your own projects do read the
-`SBT documentation
-`_.
-
-The Akka SBT build file is ``project/build/AkkaProject.scala`` with some
-properties defined in ``project/build.properties``.
-
-
-Building Akka
--------------
-
-First make sure that you are in the akka code directory::
-
- cd akka
-
-
-Fetching dependencies
-^^^^^^^^^^^^^^^^^^^^^
-
-SBT does not fetch dependencies automatically. You need to manually do this with
-the ``update`` command::
-
- sbt update
-
-Once finished, all the dependencies for Akka will be in the ``lib_managed``
-directory under each module: akka-actor, akka-stm, and so on.
-
-*Note: you only need to run update the first time you are building the code,
-or when the dependencies have changed.*
-
-
-Building
-^^^^^^^^
-
-To compile all the Akka core modules use the ``compile`` command::
-
- sbt compile
-
-You can run all tests with the ``test`` command::
-
- sbt test
-
-If compiling and testing are successful then you have everything working for the
-latest Akka development version.
-
-
-Publish to local Ivy repository
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-If you want to deploy the artifacts to your local Ivy repository (for example,
-to use from an SBT project) use the ``publish-local`` command::
-
- sbt publish-local
-
-
-Publish to local Maven repository
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-If you want to deploy the artifacts to your local Maven repository use::
-
- sbt publish-local publish
-
-
-SBT interactive mode
-^^^^^^^^^^^^^^^^^^^^
-
-Note that in the examples above we are calling ``sbt compile`` and ``sbt test``
-and so on. SBT also has an interactive mode. If you just run ``sbt`` you enter
-the interactive SBT prompt and can enter the commands directly. This saves
-starting up a new JVM instance for each command and can be much faster and more
-convenient.
-
-For example, building Akka as above is more commonly done like this:
-
-.. code-block:: none
-
- % sbt
- [info] Building project akka 1.1-SNAPSHOT against Scala 2.9.0.RC1
- [info] using AkkaParentProject with sbt 0.7.6.RC0 and Scala 2.7.7
- > update
- [info]
- [info] == akka-actor / update ==
- ...
- [success] Successful.
- [info]
- [info] Total time ...
- > compile
- ...
- > test
- ...
-
-
-SBT batch mode
-^^^^^^^^^^^^^^
-
-It's also possible to combine commands in a single call. For example, updating,
-testing, and publishing Akka to the local Ivy repository can be done with::
-
- sbt update test publish-local
-
-
-Building Akka Modules
----------------------
-
-To build Akka Modules first build and publish Akka to your local Ivy repository
-as described above. Or using::
-
- cd akka
- sbt update publish-local
-
-Then you can build Akka Modules using the same steps as building Akka. First
-update to get all dependencies (including the Akka core modules), then compile,
-test, or publish-local as needed. For example::
-
- cd akka-modules
- sbt update publish-local
-
-
-Microkernel distribution
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-To build the Akka Modules microkernel (the same as the Akka Modules distribution
-download) use the ``dist`` command::
-
- sbt dist
-
-The distribution zip can be found in the dist directory and is called
-``akka-modules-{version}.zip``.
-
-To run the mircokernel, unzip the zip file, change into the unzipped directory,
-set the ``AKKA_HOME`` environment variable, and run the main jar file. For
-example:
-
-.. code-block:: none
-
- unzip dist/akka-modules-1.1-SNAPSHOT.zip
- cd akka-modules-1.1-SNAPSHOT
- export AKKA_HOME=`pwd`
- java -jar akka-modules-1.1-SNAPSHOT.jar
-
-The microkernel will boot up and install the sample applications that reside in
-the distribution's ``deploy`` directory. You can deploy your own applications
-into the ``deploy`` directory as well.
-
-
-Scripts
--------
-
-Linux/Unix init script
-^^^^^^^^^^^^^^^^^^^^^^
-
-Here is a Linux/Unix init script that can be very useful:
-
-http://github.com/jboner/akka/blob/master/scripts/akka-init-script.sh
-
-Copy and modify as needed.
-
-
-Simple startup shell script
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-This little script might help a bit. Just make sure you have the Akka
-distribution in the '$AKKA_HOME/dist' directory and then invoke this script to
-start up the kernel. The distribution is created in the './dist' dir for you if
-you invoke 'sbt dist'.
-
-http://github.com/jboner/akka/blob/master/scripts/run_akka.sh
-
-Copy and modify as needed.
-
-
-Dependencies
-------------
-
-If you are managing dependencies by hand you can find out what all the compile
-dependencies are for each module by looking in the ``lib_managed/compile``
-directories. For example, you can run this to create a listing of dependencies
-(providing you have the source code and have run ``sbt update``)::
-
- cd akka
- ls -1 */lib_managed/compile
-
-
-Dependencies used by the Akka core modules
-------------------------------------------
-
-akka-actor
-^^^^^^^^^^
-
-* No dependencies
-
-akka-stm
-^^^^^^^^
-
-* Depends on akka-actor
-* multiverse-alpha-0.6.2.jar
-
-akka-typed-actor
-^^^^^^^^^^^^^^^^
-
-* Depends on akka-stm
-* aopalliance-1.0.jar
-* aspectwerkz-2.2.3.jar
-* guice-all-2.0.jar
-
-akka-remote
-^^^^^^^^^^^
-
-* Depends on akka-typed-actor
-* commons-codec-1.4.jar
-* commons-io-2.0.1.jar
-* dispatch-json_2.8.1-0.7.8.jar
-* guice-all-2.0.jar
-* h2-lzf-1.0.jar
-* jackson-core-asl-1.7.1.jar
-* jackson-mapper-asl-1.7.1.jar
-* junit-4.8.1.jar
-* netty-3.2.3.Final.jar
-* objenesis-1.2.jar
-* protobuf-java-2.3.0.jar
-* sjson_2.8.1-0.9.1.jar
-
-akka-http
-^^^^^^^^^
-
-* Depends on akka-remote
-* jsr250-api-1.0.jar
-* jsr311-api-1.1.jar
-
-
-Dependencies used by the Akka modules
--------------------------------------
-
-akka-amqp
-^^^^^^^^^
-
-* Depends on akka-remote
-* commons-cli-1.1.jar
-* amqp-client-1.8.1.jar
-
-akka-camel
-^^^^^^^^^^
-
-* Depends on akka-actor
-* camel-core-2.5.0.jar
-* commons-logging-api-1.1.jar
-* commons-management-1.0.jar
-
-akka-camel-typed
-^^^^^^^^^^^^^^^^
-
-* Depends on akka-typed-actor
-* camel-core-2.5.0.jar
-* commons-logging-api-1.1.jar
-* commons-management-1.0.jar
-
-akka-spring
-^^^^^^^^^^^
-
-* Depends on akka-camel
-* akka-camel-typed
-* commons-logging-1.1.1.jar
-* spring-aop-3.0.4.RELEASE.jar
-* spring-asm-3.0.4.RELEASE.jar
-* spring-beans-3.0.4.RELEASE.jar
-* spring-context-3.0.4.RELEASE.jar
-* spring-core-3.0.4.RELEASE.jar
-* spring-expression-3.0.4.RELEASE.jar
-
-akka-scalaz
-^^^^^^^^^^^
-
-* Depends on akka-actor
-* hawtdispatch-1.1.jar
-* hawtdispatch-scala-1.1.jar
-* scalaz-core_2.8.1-6.0-SNAPSHOT.jar
-
-akka-kernel
-^^^^^^^^^^^
-
-* Depends on akka-http, akka-amqp, and akka-spring
-* activation-1.1.jar
-* asm-3.1.jar
-* jaxb-api-2.1.jar
-* jaxb-impl-2.1.12.jar
-* jersey-core-1.3.jar
-* jersey-json-1.3.jar
-* jersey-scala-1.3.jar
-* jersey-server-1.3.jar
-* jettison-1.1.jar
-* jetty-continuation-7.1.6.v20100715.jar
-* jetty-http-7.1.6.v20100715.jar
-* jetty-io-7.1.6.v20100715.jar
-* jetty-security-7.1.6.v20100715.jar
-* jetty-server-7.1.6.v20100715.jar
-* jetty-servlet-7.1.6.v20100715.jar
-* jetty-util-7.1.6.v20100715.jar
-* jetty-xml-7.1.6.v20100715.jar
-* servlet-api-2.5.jar
-* stax-api-1.0.1.jar
diff --git a/akka-docs/intro/getting-started-first-java.rst b/akka-docs/intro/getting-started-first-java.rst
index df032a8970..aafe02446f 100644
--- a/akka-docs/intro/getting-started-first-java.rst
+++ b/akka-docs/intro/getting-started-first-java.rst
@@ -19,14 +19,25 @@ We will be using an algorithm that is called "embarrassingly parallel" which jus
Here is the formula for the algorithm we will use:
-.. image:: pi-formula.png
+.. image:: ../images/pi-formula.png
In this particular algorithm the master splits the series into chunks which are sent out to each worker actor to be processed. When each worker has processed its chunk it sends a result back to the master which aggregates the total result.
Tutorial source code
--------------------
-If you want don't want to type in the code and/or set up a Maven project then you can check out the full tutorial from the Akka GitHub repository. It is in the ``akka-tutorials/akka-tutorial-first`` module. You can also browse it online `here `_, with the actual source code `here `_.
+If you want don't want to type in the code and/or set up a Maven project then you can check out the full tutorial from the Akka GitHub repository. It is in the ``akka-tutorials/akka-tutorial-first`` module. You can also browse it online `here`__, with the actual source code `here`__.
+
+__ https://github.com/jboner/akka/tree/master/akka-tutorials/akka-tutorial-first
+__ https://github.com/jboner/akka/blob/master/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java
+
+To check out the code using Git invoke the following::
+
+ $ git clone git://github.com/jboner/akka.git
+
+Then you can navigate down to the tutorial::
+
+ $ cd akka/akka-tutorials/akka-tutorial-first
Prerequisites
-------------
@@ -282,7 +293,7 @@ The only thing missing in our ``Worker`` actor is the implementation on the ``ca
private double calculatePiFor(int start, int nrOfElements) {
double acc = 0.0;
for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
- acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1);
+ acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1);
}
return acc;
}
@@ -550,7 +561,7 @@ Before we package it up and run it, let's take a look at the full code now, with
private double calculatePiFor(int start, int nrOfElements) {
double acc = 0.0;
for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
- acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1);
+ acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1);
}
return acc;
}
diff --git a/akka-docs/intro/getting-started-first-scala-eclipse.rst b/akka-docs/intro/getting-started-first-scala-eclipse.rst
index d34f242e7d..b4380490ef 100644
--- a/akka-docs/intro/getting-started-first-scala-eclipse.rst
+++ b/akka-docs/intro/getting-started-first-scala-eclipse.rst
@@ -1,10 +1,12 @@
+.. _getting-started-first-scala-eclipse:
+
Getting Started Tutorial (Scala with Eclipse): First Chapter
============================================================
Introduction
------------
-Welcome to the first tutorial on how to get started with Akka and Scala. We assume that you already know what Akka and Scala are and will now focus on the steps necessary to start your first project. We will be using `Eclipse `_, and the `Scala plugin for Eclipse `_.
+Welcome to the first tutorial on how to get started with Akka and Scala. We assume that you already know what Akka and Scala are and will now focus on the steps necessary to start your first project. We will be using `Eclipse `_, and the `Scala plugin for Eclipse `_.
The sample application that we will create is using actors to calculate the value of Pi. Calculating Pi is a CPU intensive operation and we will utilize Akka Actors to write a concurrent solution that scales out to multi-core processors. This sample will be extended in future tutorials to use Akka Remote Actors to scale out on multiple machines in a cluster.
@@ -12,14 +14,17 @@ We will be using an algorithm that is called "embarrassingly parallel" which jus
Here is the formula for the algorithm we will use:
-.. image:: pi-formula.png
+.. image:: ../images/pi-formula.png
In this particular algorithm the master splits the series into chunks which are sent out to each worker actor to be processed. When each worker has processed its chunk it sends a result back to the master which aggregates the total result.
Tutorial source code
--------------------
-If you want don't want to type in the code and/or set up an SBT project then you can check out the full tutorial from the Akka GitHub repository. It is in the ``akka-tutorials/akka-tutorial-first`` module. You can also browse it online `here `_, with the actual source code `here `_.
+If you want don't want to type in the code and/or set up an SBT project then you can check out the full tutorial from the Akka GitHub repository. It is in the ``akka-tutorials/akka-tutorial-first`` module. You can also browse it online `here`__, with the actual source code `here`__.
+
+__ https://github.com/jboner/akka/tree/master/akka-tutorials/akka-tutorial-first
+__ https://github.com/jboner/akka/blob/master/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala
Prerequisites
-------------
@@ -99,19 +104,19 @@ If you want to use Eclipse for coding your Akka tutorial, you need to install th
You can install this plugin using the regular update mechanism. First choose a version of the IDE from `http://download.scala-ide.org `_. We recommend you choose 2.0.x, which comes with Scala 2.9. Copy the corresponding URL and then choose ``Help/Install New Software`` and paste the URL you just copied. You should see something similar to the following image.
-.. image:: install-beta2-updatesite.png
+.. image:: ../images/install-beta2-updatesite.png
Make sure you select both the ``JDT Weaving for Scala`` and the ``Scala IDE for Eclipse`` plugins. The other plugin is optional, and contains the source code of the plugin itself.
Once the installation is finished, you need to restart Eclipse. The first time the plugin starts it will open a diagnostics window and offer to fix several settings, such as the delay for content assist (code-completion) or the shown completion proposal types.
-.. image:: diagnostics-window.png
+.. image:: ../images/diagnostics-window.png
Accept the recommended settings, and follow the instructions if you need to increase the heap size of Eclipse.
-Check that the installation succeeded by creating a new Scala project (``File/New>Scala Project``), and typing some code. You should have content-assist, hyperlinking to definitions, instant error reporting, and so on.
+Check that the installation succeeded by creating a new Scala project (``File/New>Scala Project``), and typing some code. You should have content-assist, hyperlinking to definitions, instant error reporting, and so on.
-.. image:: example-code.png
+.. image:: ../images/example-code.png
You are ready to code now!
@@ -140,15 +145,15 @@ Creating an Akka project in Eclipse
If you have not already done so, now is the time to create an Eclipse project for our tutorial. Use the ``New Scala Project`` wizard and accept the default settings. Once the project is open, we need to add the akka libraries to the *build path*. Right click on the project and choose ``Properties``, then click on ``Java Build Path``. Go to ``Libraries`` and click on ``Add External Jars..``, then navigate to the location where you installed akka and choose ``akka-actor.jar``. You should see something similar to this:
-.. image:: build-path.png
+.. image:: ../images/build-path.png
Using SBT in Eclipse
^^^^^^^^^^^^^^^^^^^^
If you are an `SBT `_ user, you can follow the :doc:`Akka Tutorial in Scala ` and additionally install the ``sbt-eclipse`` plugin. This adds support for generating Eclipse project files from your SBT project. You need to update your SBT plugins definition in ``project/plugins``::
- import sbt._
-
+ import sbt._
+
class TutorialPlugins(info: ProjectInfo) extends PluginDefinition(info) {
// eclipsify plugin
lazy val eclipse = "de.element34" % "sbt-eclipsify" % "0.7.0"
@@ -161,8 +166,8 @@ and then update your SBT project definition by mixing in ``Eclipsify`` in your p
import sbt._
import de.element34.sbteclipsify._
-
- class MySbtProject(info: ProjectInfo) extends DefaultProject(info)
+
+ class MySbtProject(info: ProjectInfo) extends DefaultProject(info)
with Eclipsify with AkkaProject {
// the project definition here
// akka dependencies
@@ -173,20 +178,20 @@ Then run the ``eclipse`` target to generate the Eclipse project::
dragos@dragos-imac pi $ sbt eclipse
[info] Building project AkkaPi 1.0 against Scala 2.9.0.RC1
[info] using MySbtProject with sbt 0.7.4 and Scala 2.7.7
- [info]
+ [info]
[info] == eclipse ==
[info] Creating eclipse project...
[info] == eclipse ==
[success] Successful.
- [info]
+ [info]
[info] Total time: 0 s, completed Apr 20, 2011 2:48:03 PM
- [info]
+ [info]
[info] Total session time: 1 s, completed Apr 20, 2011 2:48:03 PM
[success] Build completed successfully.
Next you need to import this project in Eclipse, by choosing ``Eclipse/Import.. Existing Projects into Workspace``. Navigate to the directory where you defined your SBT project and choose import:
-.. image:: import-project.png
+.. image:: ../images/import-project.png
Now we have the basis for an Akka Eclipse application, so we can..
@@ -195,7 +200,7 @@ Start writing the code
The design we are aiming for is to have one ``Master`` actor initiating the computation, creating a set of ``Worker`` actors. Then it splits up the work into discrete chunks, and sends these chunks to the different workers in a round-robin fashion. The master waits until all the workers have completed their work and sent back results for aggregation. When computation is completed the master prints out the result, shuts down all workers and then itself.
-With this in mind, let's now create the messages that we want to have flowing in the system.
+With this in mind, let's now create the messages that we want to have flowing in the system.
Creating the messages
---------------------
@@ -234,7 +239,7 @@ Now we can create the worker actor. Create a new class called ``Worker`` as bef
The ``Actor`` trait is defined in ``akka.actor`` and you can either import it explicitly, or let Eclipse do it for you when it cannot resolve the ``Actor`` trait. The quick fix option (``Ctrl-F1``) will offer two options:
-.. image:: quickfix.png
+.. image:: ../images/quickfix.png
Choose the Akka Actor and move on.
@@ -245,7 +250,7 @@ The only thing missing in our ``Worker`` actor is the implementation on the ``ca
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
var acc = 0.0
for (i <- start until (start + nrOfElements))
- acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1)
+ acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)
acc
}
@@ -307,11 +312,11 @@ Here is the master actor::
def receive = { ... }
- override def preStart {
+ override def preStart() {
start = System.currentTimeMillis
}
- override def postStop {
+ override def postStop() {
// tell the world that the calculation is complete
println(
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
@@ -392,7 +397,7 @@ Run it from Eclipse
-------------------
Eclipse builds your project on every save when ``Project/Build Automatically`` is set. If not, bring you project up to date by clicking ``Project/Build Project``. If there are no compilation errors, you can right-click in the editor where ``Pi`` is defined, and choose ``Run as.. /Scala application``. If everything works fine, you should see::
-
+
AKKA_HOME is defined as [/Users/jboner/tools/akka-modules-1.1-M1/]
loading config from [/Users/jboner/tools/akka-modules-1.1-M1/config/akka.conf].
@@ -403,7 +408,7 @@ If you have not defined an the ``AKKA_HOME`` environment variable then Akka can'
You can also define a new Run configuration, by going to ``Run/Run Configurations``. Create a new ``Scala application`` and choose the tutorial project and the main class to be ``akkatutorial.Pi``. You can pass additional command line arguments to the JVM on the ``Arguments`` page, for instance to define where ``akka.conf`` is:
-.. image:: run-config.png
+.. image:: ../images/run-config.png
Once you finished your run configuration, click ``Run``. You should see the same output in the ``Console`` window. You can use the same configuration for debugging the application, by choosing ``Run/Debug History`` or just ``Debug As``.
diff --git a/akka-docs/intro/getting-started-first-scala.rst b/akka-docs/intro/getting-started-first-scala.rst
index 17c4d265c4..20e592c4ea 100644
--- a/akka-docs/intro/getting-started-first-scala.rst
+++ b/akka-docs/intro/getting-started-first-scala.rst
@@ -19,14 +19,25 @@ We will be using an algorithm that is called "embarrassingly parallel" which jus
Here is the formula for the algorithm we will use:
-.. image:: pi-formula.png
+.. image:: ../images/pi-formula.png
In this particular algorithm the master splits the series into chunks which are sent out to each worker actor to be processed. When each worker has processed its chunk it sends a result back to the master which aggregates the total result.
Tutorial source code
--------------------
-If you want don't want to type in the code and/or set up an SBT project then you can check out the full tutorial from the Akka GitHub repository. It is in the ``akka-tutorials/akka-tutorial-first`` module. You can also browse it online `here `_, with the actual source code `here `_.
+If you want don't want to type in the code and/or set up an SBT project then you can check out the full tutorial from the Akka GitHub repository. It is in the ``akka-tutorials/akka-tutorial-first`` module. You can also browse it online `here`__, with the actual source code `here`__.
+
+__ https://github.com/jboner/akka/tree/master/akka-tutorials/akka-tutorial-first
+__ https://github.com/jboner/akka/blob/master/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala
+
+To check out the code using Git invoke the following::
+
+ $ git clone git://github.com/jboner/akka.git
+
+Then you can navigate down to the tutorial::
+
+ $ cd akka/akka-tutorials/akka-tutorial-first
Prerequisites
-------------
@@ -173,8 +184,11 @@ Not needed in this tutorial, but if you would like to use additional Akka module
So, now we are all set. Just one final thing to do; make SBT download the dependencies it needs. That is done by invoking::
+ > reload
> update
+The first reload command is needed because we have changed the project definition since the sbt session started.
+
SBT itself needs a whole bunch of dependencies but our project will only need one; ``akka-actor-1.1.jar``. SBT downloads that as well.
Start writing the code
@@ -238,7 +252,7 @@ The only thing missing in our ``Worker`` actor is the implementation on the ``ca
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
var acc = 0.0
for (i <- start until (start + nrOfElements))
- acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1)
+ acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)
acc
}
@@ -291,11 +305,11 @@ Here is the master actor::
def receive = { ... }
- override def preStart {
+ override def preStart() {
start = System.currentTimeMillis
}
- override def postStop {
+ override def postStop() {
// tell the world that the calculation is complete
println(
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
@@ -404,7 +418,7 @@ But before we package it up and run it, let's take a look at the full code now,
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
var acc = 0.0
for (i <- start until (start + nrOfElements))
- acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1)
+ acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)
acc
}
@@ -451,11 +465,11 @@ But before we package it up and run it, let's take a look at the full code now,
if (nrOfResults == nrOfMessages) self.stop()
}
- override def preStart {
+ override def preStart() {
start = System.currentTimeMillis
}
- override def postStop {
+ override def postStop() {
// tell the world that the calculation is complete
println(
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
diff --git a/akka-docs/intro/index.rst b/akka-docs/intro/index.rst
index 8df1a87a5d..6550f1bd79 100644
--- a/akka-docs/intro/index.rst
+++ b/akka-docs/intro/index.rst
@@ -8,5 +8,3 @@ Introduction
getting-started-first-scala
getting-started-first-scala-eclipse
getting-started-first-java
- building-akka
- configuration
diff --git a/akka-docs/pending/actor-registry-java.rst b/akka-docs/java/actor-registry.rst
similarity index 100%
rename from akka-docs/pending/actor-registry-java.rst
rename to akka-docs/java/actor-registry.rst
diff --git a/akka-docs/pending/dispatchers-java.rst b/akka-docs/java/dispatchers.rst
similarity index 95%
rename from akka-docs/pending/dispatchers-java.rst
rename to akka-docs/java/dispatchers.rst
index 7889db30fc..a7fe7ce19a 100644
--- a/akka-docs/pending/dispatchers-java.rst
+++ b/akka-docs/java/dispatchers.rst
@@ -1,6 +1,10 @@
Dispatchers (Java)
==================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
The Dispatcher is an important piece that allows you to configure the right semantics and parameters for optimal performance, throughput and scalability. Different Actors have different needs.
@@ -128,7 +132,7 @@ If you don't define a the 'throughput' option in the configuration file then the
Browse the `ScalaDoc `_ or look at the code for all the options available.
Priority event-based
-^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^
Sometimes it's useful to be able to specify priority order of messages, that is done by using PriorityExecutorBasedEventDrivenDispatcher and supply
a java.util.Comparator[MessageInvocation] or use a akka.dispatch.PriorityGenerator (recommended):
@@ -137,7 +141,7 @@ Creating a PriorityExecutorBasedEventDrivenDispatcher using PriorityGenerator:
.. code-block:: java
- package some.package;
+ package some.pkg;
import akka.actor.*;
import akka.dispatch.*;
@@ -165,7 +169,7 @@ Creating a PriorityExecutorBasedEventDrivenDispatcher using PriorityGenerator:
ref.setDispatcher(new PriorityExecutorBasedEventDrivenDispatcher("foo", gen));
ref.start(); // Start the actor
- ref.getDispatcher().suspend(ref); // Suspening the actor so it doesn't start to treat the messages before we have enqueued all of them :-)
+ ref.getDispatcher().suspend(ref); // Suspending the actor so it doesn't start to treat the messages before we have enqueued all of them :-)
ref.sendOneWay("lowpriority");
ref.sendOneWay("lowpriority");
ref.sendOneWay("highpriority");
@@ -249,13 +253,14 @@ For the 'ExecutorBasedEventDrivenDispatcher' and the 'ExecutorBasedWorkStealingD
For the 'ThreadBasedDispatcher', it is non-shareable between actors, and associates a dedicated Thread with the actor.
Making it bounded (by specifying a capacity) is optional, but if you do, you need to provide a pushTimeout (default is 10 seconds). When trying to send a message to the Actor it will throw a MessageQueueAppendFailedException("BlockingMessageTransferQueue transfer timed out") if the message cannot be added to the mailbox within the time specified by the pushTimeout.
-``_
-class MyActor extends UntypedActor {
- public MyActor() {
- int mailboxCapacity = 100;
- Duration pushTimeout = new FiniteDuration(10, TimeUnit.SECONDS);
- getContext().setDispatcher(Dispatchers.newThreadBasedDispatcher(getContext(), mailboxCapacity, pushTimeout));
+.. code-block:: java
+
+ class MyActor extends UntypedActor {
+ public MyActor() {
+ int mailboxCapacity = 100;
+ Duration pushTimeout = new FiniteDuration(10, TimeUnit.SECONDS);
+ getContext().setDispatcher(Dispatchers.newThreadBasedDispatcher(getContext(), mailboxCapacity, pushTimeout));
+ }
+ ...
}
- ...
-}
-``_
+
diff --git a/akka-docs/java/index.rst b/akka-docs/java/index.rst
new file mode 100644
index 0000000000..553f75da45
--- /dev/null
+++ b/akka-docs/java/index.rst
@@ -0,0 +1,14 @@
+Java API
+=========
+
+.. toctree::
+ :maxdepth: 2
+
+ untyped-actors
+ typed-actors
+ actor-registry
+ stm
+ transactors
+ remote-actors
+ serialization
+ dispatchers
diff --git a/akka-docs/pending/remote-actors-java.rst b/akka-docs/java/remote-actors.rst
similarity index 73%
rename from akka-docs/pending/remote-actors-java.rst
rename to akka-docs/java/remote-actors.rst
index 0e654fc698..3894f2dacc 100644
--- a/akka-docs/pending/remote-actors-java.rst
+++ b/akka-docs/java/remote-actors.rst
@@ -1,11 +1,15 @@
Remote Actors (Java)
====================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
-Akka supports starting UntypedActors and TypedActors on remote nodes using a very efficient and scalable NIO implementation built upon `JBoss Netty `_ and `Google Protocol Buffers `_ .
+Akka supports starting interacting with UntypedActors and TypedActors on remote nodes using a very efficient and scalable NIO implementation built upon `JBoss Netty `_ and `Google Protocol Buffers `_ .
-The usage is completely transparent both in regards to sending messages and error handling and propagation as well as supervision, linking and restarts. You can send references to other Actors as part of the message.
+The usage is completely transparent with local actors, both in regards to sending messages and error handling and propagation as well as supervision, linking and restarts. You can send references to other Actors as part of the message.
**WARNING**: For security reasons, do not run an Akka node with a Remote Actor port reachable by untrusted connections unless you have supplied a classloader that restricts access to the JVM.
@@ -15,7 +19,7 @@ Managing the Remote Service
Starting remote service in user code as a library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Here is how to start up the server and specify the hostname and port programatically:
+Here is how to start up the server and specify the hostname and port programmatically:
.. code-block:: java
@@ -142,12 +146,6 @@ The default behavior is that the remote client will maintain a transaction log o
If you choose a capacity higher than 0, then a bounded queue will be used and if the limit of the queue is reached then a 'RemoteClientMessageBufferException' will be thrown.
-You can also get an Array with all the messages that the remote client has failed to send. Since the remote client events passes you an instance of the RemoteClient you have an easy way to act upon failure and do something with these messages (while waiting for them to be retried).
-
-.. code-block:: java
-
- Object[] pending = Actors.remote().pendingMessages();
-
Running Remote Server in untrusted mode
---------------------------------------
@@ -253,21 +251,13 @@ You can also generate the secure cookie by using the 'Crypt' object and its 'gen
The secure cookie is a cryptographically secure randomly generated byte array turned into a SHA-1 hash.
-Remote Actors
--------------
-
-Akka has two types of remote actors:
-
-* Client-initiated and managed. Here it is the client that creates the remote actor and "moves it" to the server.
-* Server-initiated and managed. Here it is the server that creates the remote actor and the client can ask for a handle to this actor.
-
-They are good for different use-cases. The client-initiated are great when you want to monitor an actor on another node since it allows you to link to it and supervise it using the regular supervision semantics. They also make RPC completely transparent. The server-initiated, on the other hand, are great when you have a service running on the server that you want clients to connect to, and you want full control over the actor on the server side for security reasons etc.
-
Client-managed Remote UntypedActor
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+----------------------------------
DEPRECATED AS OF 1.1
+The client creates the remote actor and "moves it" to the server.
+
When you define an actors as being remote it is instantiated as on the remote host and your local actor becomes a proxy, it works as a handle to the remote actor. The real execution is always happening on the remote node.
Here is an example:
@@ -291,30 +281,35 @@ An UntypedActor can also start remote child Actors through one of the “spawn/l
.. code-block:: java
...
- getContext().spawnRemote(MyActor.class, hostname, port);
+ getContext().spawnRemote(MyActor.class, hostname, port, timeoutInMsForFutures);
getContext().spawnLinkRemote(MyActor.class, hostname, port, timeoutInMsForFutures);
...
Server-managed Remote UntypedActor
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+----------------------------------
+
+Here it is the server that creates the remote actor and the client can ask for a handle to this actor.
Server side setup
-*****************
+^^^^^^^^^^^^^^^^^
The API for server managed remote actors is really simple. 2 methods only:
.. code-block:: java
+ import akka.actor.Actors;
+ import akka.actor.UntypedActor;
+
class MyActor extends UntypedActor {
public void onReceive(Object message) throws Exception {
...
}
}
- Actors.remote().start("localhost", 2552).register("hello-service", Actors.actorOf(HelloWorldActor.class);
+ Actors.remote().start("localhost", 2552).register("hello-service", Actors.actorOf(HelloWorldActor.class));
Actors created like this are automatically started.
-You can also register an actor by its UUD rather than ID or handle. This is done by prefixing the handle with the "uuid:" protocol.
+You can also register an actor by its UUID rather than ID or handle. This is done by prefixing the handle with the "uuid:" protocol.
.. code-block:: scala
@@ -322,88 +317,6 @@ You can also register an actor by its UUD rather than ID or handle. This is done
server.unregister("uuid:" + actor.uuid);
-Client side usage
-*****************
-
-.. code-block:: java
-
- ActorRef actor = Actors.remote().actorFor("hello-service", "localhost", 2552);
- actor.sendOneWay("Hello");
-
-There are many variations on the 'remote()#actorFor' method. Here are some of them:
-
-.. code-block:: java
-
- ... = actorFor(className, hostname, port);
- ... = actorFor(className, timeout, hostname, port);
- ... = actorFor(uuid, className, hostname, port);
- ... = actorFor(uuid, className, timeout, hostname, port);
- ... // etc
-
-All of these also have variations where you can pass in an explicit 'ClassLoader' which can be used when deserializing messages sent from the remote actor.
-
-Client-managed Remote TypedActor
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-DEPRECATED AS OF 1.1
-
-Remote Typed Actors are created through the 'TypedActor.newRemoteInstance' factory method.
-
-.. code-block:: java
-
- MyPOJO remoteActor = (MyPOJO)TypedActor.newRemoteInstance(MyPOJO.class, MyPOJOImpl.class, , "localhost", 2552);
-
-And if you want to specify the timeout:
-
-.. code-block:: java
-
- MyPOJO remoteActor = (MyPOJO)TypedActor.newRemoteInstance(MyPOJO.class, MyPOJOImpl.class, timeout, "localhost", 2552);
-
-You can also define the Typed Actor to be a client-managed-remote service by adding the ‘RemoteAddress’ configuration element in the declarative supervisor configuration:
-
-.. code-block:: java
-
- new Component(
- Foo.class,
- FooImpl.class,
- new LifeCycle(new Permanent(), 1000),
- 1000,
- new RemoteAddress("localhost", 2552))
-
-Server-managed Remote TypedActor
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-WARNING: Remote TypedActors do not work with overloaded methods on your TypedActor, refrain from using overloading.
-
-Server side setup
-*****************
-
-The API for server managed remote typed actors is nearly the same as for untyped actor:
-
-.. code-block:: java
-
- import static akka.actor.Actors.*;
- remote().start("localhost", 2552);
-
- RegistrationService typedActor = TypedActor.newInstance(RegistrationService.class, RegistrationServiceImpl.class, 2000);
- remote().registerTypedActor("user-service", typedActor);
-
-Client side usage
-
-.. code-block:: java
-
- import static akka.actor.Actors.*;
- RegistrationService actor = remote().typedActorFor(RegistrationService.class, "user-service", 5000L, "localhost", 2552);
- actor.registerUser(...);
-
-There are variations on the 'remote()#typedActorFor' method. Here are some of them:
-
-.. code-block:: java
-
- ... = typedActorFor(interfaceClazz, serviceIdOrClassName, hostname, port);
- ... = typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port);
- ... = typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port, classLoader);
-
Session bound server side setup
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -414,17 +327,19 @@ Session bound actors are useful if you need to keep state per session, e.g. user
.. code-block:: java
import static akka.actor.Actors.*;
+ import akka.japi.Creator;
+
class HelloWorldActor extends Actor {
...
}
remote().start("localhost", 2552);
- remote().registerPerSession("hello-service", new Creator[ActorRef]() {
+ remote().registerPerSession("hello-service", new Creator() {
public ActorRef create() {
return actorOf(HelloWorldActor.class);
}
- })
+ });
Note that the second argument in registerPerSession is a Creator, it means that the create method will create a new ActorRef each invocation.
It will be called to create an actor every time a session is established.
@@ -443,19 +358,22 @@ There are many variations on the 'remote()#actorFor' method. Here are some of th
.. code-block:: java
- ... = actorFor(className, hostname, port);
- ... = actorFor(className, timeout, hostname, port);
- ... = actorFor(uuid, className, hostname, port);
- ... = actorFor(uuid, className, timeout, hostname, port);
+ ... = remote().actorFor(className, hostname, port);
+ ... = remote().actorFor(className, timeout, hostname, port);
+ ... = remote().actorFor(uuid, className, hostname, port);
+ ... = remote().actorFor(uuid, className, timeout, hostname, port);
... // etc
-Automatic remote 'sender' reference management
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+All of these also have variations where you can pass in an explicit 'ClassLoader' which can be used when deserializing messages sent from the remote actor.
-Akka is automatically remote-enabling the sender Actor reference for you in order to allow the receiver to respond to the message using 'getContext().getSender().sendOneWay(msg);' or 'getContext().reply(msg);'. By default it is registering the sender reference in the remote server with the 'hostname' and 'port' from the akka.conf configuration file. The default is "localhost" and 2552 and if there is no remote server with this hostname and port then it creates and starts it.
+Automatic remote 'sender' reference management
+----------------------------------------------
+
+The sender of a remote message will be reachable with a reply through the remote server on the node that the actor is residing, automatically.
+Please note that firewalled clients won't work right now. [2011-01-05]
Identifying remote actors
-^^^^^^^^^^^^^^^^^^^^^^^^^
+-------------------------
The 'id' field in the 'Actor' class is of importance since it is used as identifier for the remote actor. If you want to create a brand new actor every time you instantiate a remote actor then you have to set the 'id' field to a unique 'String' for each instance. If you want to reuse the same remote actor instance for each new remote actor (of the same class) you create then you don't have to do anything since the 'id' field by default is equal to the name of the actor class.
@@ -463,18 +381,83 @@ Here is an example of overriding the 'id' field:
.. code-block:: java
- import akka.util.UUID;
+ import akka.actor.UntypedActor;
+ import com.eaio.uuid.UUID;
class MyActor extends UntypedActor {
public MyActor() {
- getContext().setId(UUID.newUuid().toString());
+ getContext().setId(new UUID().toString());
}
public void onReceive(Object message) throws Exception {
- ...
+ // ...
}
}
+Client-managed Remote Typed Actors
+----------------------------------
+
+DEPRECATED AS OF 1.1
+
+Remote Typed Actors are created through the 'TypedActor.newRemoteInstance' factory method.
+
+.. code-block:: java
+
+ MyPOJO remoteActor = (MyPOJO) TypedActor.newRemoteInstance(MyPOJO.class, MyPOJOImpl.class, "localhost", 2552);
+
+And if you want to specify the timeout:
+
+.. code-block:: java
+
+ MyPOJO remoteActor = (MyPOJO)TypedActor.newRemoteInstance(MyPOJO.class, MyPOJOImpl.class, timeout, "localhost", 2552);
+
+You can also define the Typed Actor to be a client-managed-remote service by adding the ‘RemoteAddress’ configuration element in the declarative supervisor configuration:
+
+.. code-block:: java
+
+ new Component(
+ Foo.class,
+ FooImpl.class,
+ new LifeCycle(new Permanent(), 1000),
+ 1000,
+ new RemoteAddress("localhost", 2552))
+
+Server-managed Remote Typed Actors
+----------------------------------
+
+WARNING: Remote TypedActors do not work with overloaded methods on your TypedActor, refrain from using overloading.
+
+Server side setup
+^^^^^^^^^^^^^^^^^
+
+The API for server managed remote typed actors is nearly the same as for untyped actor:
+
+.. code-block:: java
+
+ import static akka.actor.Actors.*;
+ remote().start("localhost", 2552);
+
+ RegistrationService typedActor = TypedActor.newInstance(RegistrationService.class, RegistrationServiceImpl.class, 2000);
+ remote().registerTypedActor("user-service", typedActor);
+
+
+Client side usage
+^^^^^^^^^^^^^^^^^
+
+.. code-block:: java
+
+ import static akka.actor.Actors.*;
+ RegistrationService actor = remote().typedActorFor(RegistrationService.class, "user-service", 5000L, "localhost", 2552);
+ actor.registerUser(...);
+
+There are variations on the 'remote()#typedActorFor' method. Here are some of them:
+
+.. code-block:: java
+
+ ... = remote().typedActorFor(interfaceClazz, serviceIdOrClassName, hostname, port);
+ ... = remote().typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port);
+ ... = remote().typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port, classLoader);
+
Data Compression Configuration
------------------------------
@@ -493,44 +476,55 @@ You can configure it like this:
}
}
+Code provisioning
+-----------------
+
+Akka does currently not support automatic code provisioning but requires you to have the remote actor class files available on both the "client" the "server" nodes.
+This is something that will be addressed soon. Until then, sorry for the inconvenience.
+
Subscribe to Remote Client events
---------------------------------
Akka has a subscription API for remote client events. You can register an Actor as a listener and this actor will have to be able to process these events:
-RemoteClientError { Throwable cause; RemoteClientModule client; InetSocketAddress remoteAddress; }
-RemoteClientDisconnected { RemoteClientModule client; InetSocketAddress remoteAddress; }
-RemoteClientConnected { RemoteClientModule client; InetSocketAddress remoteAddress; }
-RemoteClientStarted { RemoteClientModule client; InetSocketAddress remoteAddress; }
-RemoteClientShutdown { RemoteClientModule client; InetSocketAddress remoteAddress; }
-RemoteClientWriteFailed { Object message; Throwable cause; RemoteClientModule client; InetSocketAddress remoteAddress; }
+.. code-block:: java
+
+ class RemoteClientError { Throwable cause; RemoteClientModule client; InetSocketAddress remoteAddress; }
+ class RemoteClientDisconnected { RemoteClientModule client; InetSocketAddress remoteAddress; }
+ class RemoteClientConnected { RemoteClientModule client; InetSocketAddress remoteAddress; }
+ class RemoteClientStarted { RemoteClientModule client; InetSocketAddress remoteAddress; }
+ class RemoteClientShutdown { RemoteClientModule client; InetSocketAddress remoteAddress; }
+ class RemoteClientWriteFailed { Object message; Throwable cause; RemoteClientModule client; InetSocketAddress remoteAddress; }
So a simple listener actor can look like this:
.. code-block:: java
+ import akka.actor.UntypedActor;
+ import akka.remoteinterface.*;
+
class Listener extends UntypedActor {
public void onReceive(Object message) throws Exception {
if (message instanceof RemoteClientError) {
- RemoteClientError event = (RemoteClientError)message;
- Exception cause = event.getCause();
- ...
+ RemoteClientError event = (RemoteClientError) message;
+ Throwable cause = event.getCause();
+ // ...
} else if (message instanceof RemoteClientConnected) {
- RemoteClientConnected event = (RemoteClientConnected)message;
- ...
+ RemoteClientConnected event = (RemoteClientConnected) message;
+ // ...
} else if (message instanceof RemoteClientDisconnected) {
- RemoteClientDisconnected event = (RemoteClientDisconnected)message;
- ...
+ RemoteClientDisconnected event = (RemoteClientDisconnected) message;
+ // ...
} else if (message instanceof RemoteClientStarted) {
- RemoteClientStarted event = (RemoteClientStarted)message;
- ...
+ RemoteClientStarted event = (RemoteClientStarted) message;
+ // ...
} else if (message instanceof RemoteClientShutdown) {
- RemoteClientShutdown event = (RemoteClientShutdown)message;
- ...
+ RemoteClientShutdown event = (RemoteClientShutdown) message;
+ // ...
} else if (message instanceof RemoteClientWriteFailed) {
- RemoteClientWriteFailed event = (RemoteClientWriteFailed)message;
- ...
+ RemoteClientWriteFailed event = (RemoteClientWriteFailed) message;
+ // ...
}
}
}
@@ -550,43 +544,45 @@ Subscribe to Remote Server events
Akka has a subscription API for the server events. You can register an Actor as a listener and this actor will have to be able to process these events:
-RemoteServerStarted { RemoteServerModule server; }
-RemoteServerShutdown { RemoteServerModule server; }
-RemoteServerError { Throwable cause; RemoteServerModule server; }
-RemoteServerClientConnected { RemoteServerModule server; Option clientAddress; }
-RemoteServerClientDisconnected { RemoteServerModule server; Option clientAddress; }
-RemoteServerClientClosed { RemoteServerModule server; Option clientAddress; }
-RemoteServerWriteFailed { Object request; Throwable cause; RemoteServerModule server; Option clientAddress; }
+.. code-block:: java
+
+ class RemoteServerStarted { RemoteServerModule server; }
+ class RemoteServerShutdown { RemoteServerModule server; }
+ class RemoteServerError { Throwable cause; RemoteServerModule server; }
+ class RemoteServerClientConnected { RemoteServerModule server; Option clientAddress; }
+ class RemoteServerClientDisconnected { RemoteServerModule server; Option clientAddress; }
+ class RemoteServerClientClosed { RemoteServerModule server; Option clientAddress; }
+ class RemoteServerWriteFailed { Object request; Throwable cause; RemoteServerModule server; Option clientAddress; }
So a simple listener actor can look like this:
.. code-block:: java
+ import akka.actor.UntypedActor;
+ import akka.remoteinterface.*;
+
class Listener extends UntypedActor {
public void onReceive(Object message) throws Exception {
- if (message instanceof RemoteServerError) {
- RemoteServerError event = (RemoteServerError)message;
- Exception cause = event.getCause();
- ...
- } else if (message instanceof RemoteServerStarted) {
- RemoteServerStarted event = (RemoteServerStarted)message;
- ...
- } else if (message instanceof RemoteServerShutdown) {
- RemoteServerShutdown event = (RemoteServerShutdown)message;
- ...
- } else if (message instanceof RemoteServerClientConnected) {
- RemoteServerClientConnected event = (RemoteServerClientConnected)message;
- ...
- } else if (message instanceof RemoteServerClientDisconnected) {
- RemoteServerClientDisconnected event = (RemoteServerClientDisconnected)message;
- ...
- } else if (message instanceof RemoteServerClientClosed) {
- RemoteServerClientClosed event = (RemoteServerClientClosed)message;
- ...
- } else if (message instanceof RemoteServerWriteFailed) {
- RemoteServerWriteFailed event = (RemoteServerWriteFailed)message;
- ...
+ if (message instanceof RemoteClientError) {
+ RemoteClientError event = (RemoteClientError) message;
+ Throwable cause = event.getCause();
+ // ...
+ } else if (message instanceof RemoteClientConnected) {
+ RemoteClientConnected event = (RemoteClientConnected) message;
+ // ...
+ } else if (message instanceof RemoteClientDisconnected) {
+ RemoteClientDisconnected event = (RemoteClientDisconnected) message;
+ // ...
+ } else if (message instanceof RemoteClientStarted) {
+ RemoteClientStarted event = (RemoteClientStarted) message;
+ // ...
+ } else if (message instanceof RemoteClientShutdown) {
+ RemoteClientShutdown event = (RemoteClientShutdown) message;
+ // ...
+ } else if (message instanceof RemoteClientWriteFailed) {
+ RemoteClientWriteFailed event = (RemoteClientWriteFailed) message;
+ // ...
}
}
}
@@ -608,10 +604,27 @@ Message Serialization
All messages that are sent to remote actors needs to be serialized to binary format to be able to travel over the wire to the remote node. This is done by letting your messages extend one of the traits in the 'akka.serialization.Serializable' object. If the messages don't implement any specific serialization trait then the runtime will try to use standard Java serialization.
-Read more about that in the `Serialization section `_.
+Here is one example, but full documentation can be found in the :ref:`serialization-java`.
-Code provisioning
------------------
+Protobuf
+^^^^^^^^
-Akka does currently not support automatic code provisioning but requires you to have the remote actor class files available on both the "client" the "server" nodes.
-This is something that will be addressed soon. Until then, sorry for the inconvenience.
+Protobuf message specification needs to be compiled with 'protoc' compiler.
+
+::
+
+ message ProtobufPOJO {
+ required uint64 id = 1;
+ required string name = 2;
+ required bool status = 3;
+ }
+
+Using the generated message builder to send the message to a remote actor:
+
+.. code-block:: java
+
+ actor.sendOneWay(ProtobufPOJO.newBuilder()
+ .setId(11)
+ .setStatus(true)
+ .setName("Coltrane")
+ .build());
diff --git a/akka-docs/pending/serialization-java.rst b/akka-docs/java/serialization.rst
similarity index 90%
rename from akka-docs/pending/serialization-java.rst
rename to akka-docs/java/serialization.rst
index 1206211b8d..813db45a9a 100644
--- a/akka-docs/pending/serialization-java.rst
+++ b/akka-docs/java/serialization.rst
@@ -1,10 +1,16 @@
+.. _serialization-java:
+
Serialization (Java)
====================
-Akka serialization module has been documented extensively under the Scala API section. In this section we will point out the different APIs that are available in Akka for Java based serialization of ActorRefs. The Scala APIs of ActorSerialization has implicit Format objects that set up the type class based serialization. In the Java API, the Format objects need to be specified explicitly.
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
+Akka serialization module has been documented extensively under the :ref:`serialization-scala` section. In this section we will point out the different APIs that are available in Akka for Java based serialization of ActorRefs. The Scala APIs of ActorSerialization has implicit Format objects that set up the type class based serialization. In the Java API, the Format objects need to be specified explicitly.
Serialization of ActorRef
-=========================
+-------------------------
The following are the Java APIs for serialization of local ActorRefs:
@@ -26,10 +32,9 @@ The following are the Java APIs for serialization of local ActorRefs:
The following steps describe the procedure for serializing an Actor and ActorRef.
Serialization of a Stateless Actor
-==================================
+----------------------------------
Step 1: Define the Actor
-------------------------
.. code-block:: scala
@@ -40,7 +45,6 @@ Step 1: Define the Actor
}
Step 2: Define the typeclass instance for the actor
----------------------------------------------------
Note how the generated Java classes are accessed using the $class based naming convention of the Scala compiler.
@@ -58,7 +62,7 @@ Note how the generated Java classes are accessed using the $class based naming c
}
}
-**Step 3: Serialize and de-serialize**
+Step 3: Serialize and de-serialize
The following JUnit snippet first creates an actor using the default constructor. The actor is, as we saw above a stateless one. Then it is serialized and de-serialized to get back the original actor. Being stateless, the de-serialized version behaves in the same way on a message as the original actor.
@@ -91,12 +95,11 @@ The following JUnit snippet first creates an actor using the default constructor
}
Serialization of a Stateful Actor
-=================================
+---------------------------------
Let's now have a look at how to serialize an actor that carries a state with it. Here the expectation is that the serialization of the actor will also persist the state information. And after de-serialization we will get back the state with which it was serialized.
Step 1: Define the Actor
-------------------------
Here we consider an actor defined in Scala. We will however serialize using the Java APIs.
@@ -119,7 +122,6 @@ Here we consider an actor defined in Scala. We will however serialize using the
Note the actor has a state in the form of an Integer. And every message that the actor receives, it replies with an addition to the integer member.
Step 2: Define the instance of the typeclass
---------------------------------------------
.. code-block:: java
@@ -141,7 +143,6 @@ Step 2: Define the instance of the typeclass
Note the usage of Protocol Buffers to serialize the state of the actor.
Step 3: Serialize and de-serialize
-----------------------------------
.. code-block:: java
diff --git a/akka-docs/pending/stm-java.rst b/akka-docs/java/stm.rst
similarity index 72%
rename from akka-docs/pending/stm-java.rst
rename to akka-docs/java/stm.rst
index 7873e38a7a..ed44218804 100644
--- a/akka-docs/pending/stm-java.rst
+++ b/akka-docs/java/stm.rst
@@ -1,10 +1,14 @@
Software Transactional Memory (Java)
====================================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
Overview of STM
-===============
+---------------
An `STM `_ turns the Java heap into a transactional data set with begin/commit/rollback semantics. Very much like a regular database. It implements the first three letters in ACID; ACI:
* (failure) Atomicity: all changes during the execution of a transaction make it, or none make it. This only counts for transactional datastructures.
@@ -12,9 +16,10 @@ An `STM `_ turns the
* Isolated: changes made by concurrent execution transactions are not visible to each other.
Generally, the STM is not needed that often when working with Akka. Some use-cases (that we can think of) are:
-# When you really need composable message flows across many actors updating their **internal local** state but need them to do that atomically in one big transaction. Might not often, but when you do need this then you are screwed without it.
-# When you want to share a datastructure across actors.
-# When you need to use the persistence modules.
+
+- When you really need composable message flows across many actors updating their **internal local** state but need them to do that atomically in one big transaction. Might not often, but when you do need this then you are screwed without it.
+- When you want to share a datastructure across actors.
+- When you need to use the persistence modules.
Akka’s STM implements the concept in `Clojure’s `_ STM view on state in general. Please take the time to read `this excellent document `_ and view `this presentation `_ by Rich Hickey (the genius behind Clojure), since it forms the basis of Akka’s view on STM and state in general.
@@ -23,7 +28,7 @@ The STM is based on Transactional References (referred to as Refs). Refs are mem
Working with immutable collections can sometimes give bad performance due to extensive copying. Scala provides so-called persistent datastructures which makes working with immutable collections fast. They are immutable but with constant time access and modification. The use of structural sharing and an insert or update does not ruin the old structure, hence “persistent”. Makes working with immutable composite types fast. The persistent datastructures currently consist of a Map and Vector.
Simple example
-==============
+--------------
Here is a simple example of an incremental counter using STM. This shows creating a ``Ref``, a transactional reference, and then modifying it within a transaction, which is delimited by an ``Atomic`` anonymous inner class.
@@ -49,15 +54,14 @@ Here is a simple example of an incremental counter using STM. This shows creatin
counter();
// -> 2
-----
Ref
-===
+---
Refs (transactional references) are mutable references to values and through the STM allow the safe sharing of mutable data. To ensure safety the value stored in a Ref should be immutable. The value referenced by a Ref can only be accessed or swapped within a transaction. Refs separate identity from value.
Creating a Ref
---------------
+^^^^^^^^^^^^^^
You can create a Ref with or without an initial value.
@@ -72,7 +76,7 @@ You can create a Ref with or without an initial value.
final Ref ref = new Ref();
Accessing the value of a Ref
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use ``get`` to access the value of a Ref. Note that if no initial value has been given then the value is initially ``null``.
@@ -90,7 +94,7 @@ Use ``get`` to access the value of a Ref. Note that if no initial value has been
// -> value = 0
Changing the value of a Ref
----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
To set a new value for a Ref you can use ``set`` (or equivalently ``swap``), which sets the new value and returns the old value.
@@ -106,10 +110,9 @@ To set a new value for a Ref you can use ``set`` (or equivalently ``swap``), whi
}
}.execute();
-----
Transactions
-============
+------------
A transaction is delimited using an ``Atomic`` anonymous inner class.
@@ -124,24 +127,24 @@ A transaction is delimited using an ``Atomic`` anonymous inner class.
All changes made to transactional objects are isolated from other changes, all make it or non make it (so failure atomicity) and are consistent. With the AkkaSTM you automatically have the Oracle version of the SERIALIZED isolation level, lower isolation is not possible. To make it fully serialized, set the writeskew property that checks if a writeskew problem is allowed to happen.
Retries
--------
+^^^^^^^
A transaction is automatically retried when it runs into some read or write conflict, until the operation completes, an exception (throwable) is thrown or when there are too many retries. When a read or writeconflict is encountered, the transaction uses a bounded exponential backoff to prevent cause more contention and give other transactions some room to complete.
If you are using non transactional resources in an atomic block, there could be problems because a transaction can be retried. If you are using print statements or logging, it could be that they are called more than once. So you need to be prepared to deal with this. One of the possible solutions is to work with a deferred or compensating task that is executed after the transaction aborts or commits.
Unexpected retries
-------------------
+^^^^^^^^^^^^^^^^^^
It can happen for the first few executions that you get a few failures of execution that lead to unexpected retries, even though there is not any read or writeconflict. The cause of this is that speculative transaction configuration/selection is used. There are transactions optimized for a single transactional object, for 1..n and for n to unlimited. So based on the execution of the transaction, the system learns; it begins with a cheap one and upgrades to more expensive ones. Once it has learned, it will reuse this knowledge. It can be activated/deactivated using the speculative property on the TransactionFactoryBuilder. In most cases it is best use the default value (enabled) so you get more out of performance.
Coordinated transactions and Transactors
-----------------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-If you need coordinated transactions across actors or threads then see `Transactors `_.
+If you need coordinated transactions across actors or threads then see :ref:`transactors-java`.
Configuring transactions
-------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^
It's possible to configure transactions. The ``Atomic`` class can take a ``TransactionFactory``, which can determine properties of the transaction. A default transaction factory is used if none is specified. You can create a ``TransactionFactory`` with a ``TransactionFactoryBuilder``.
@@ -163,37 +166,40 @@ Configuring transactions with a ``TransactionFactory``:
}.execute();
The following settings are possible on a TransactionFactory:
-* familyName - Family name for transactions. Useful for debugging because the familyName is shown in exceptions, logging and in the future also will be used for profiling.
-* readonly - Sets transaction as readonly. Readonly transactions are cheaper and can be used to prevent modification to transactional objects.
-* maxRetries - The maximum number of times a transaction will retry.
-* timeout - The maximum time a transaction will block for.
-* trackReads - Whether all reads should be tracked. Needed for blocking operations. Readtracking makes a transaction more expensive, but makes subsequent reads cheaper and also lowers the chance of a readconflict.
-* writeSkew - Whether writeskew is allowed. Disable with care.
-* blockingAllowed - Whether explicit retries are allowed.
-* interruptible - Whether a blocking transaction can be interrupted if it is blocked.
-* speculative - Whether speculative configuration should be enabled.
-* quickRelease - Whether locks should be released as quickly as possible (before whole commit).
-* propagation - For controlling how nested transactions behave.
-* traceLevel - Transaction trace level.
+
+- familyName - Family name for transactions. Useful for debugging because the familyName is shown in exceptions, logging and in the future also will be used for profiling.
+- readonly - Sets transaction as readonly. Readonly transactions are cheaper and can be used to prevent modification to transactional objects.
+- maxRetries - The maximum number of times a transaction will retry.
+- timeout - The maximum time a transaction will block for.
+- trackReads - Whether all reads should be tracked. Needed for blocking operations. Readtracking makes a transaction more expensive, but makes subsequent reads cheaper and also lowers the chance of a readconflict.
+- writeSkew - Whether writeskew is allowed. Disable with care.
+- blockingAllowed - Whether explicit retries are allowed.
+- interruptible - Whether a blocking transaction can be interrupted if it is blocked.
+- speculative - Whether speculative configuration should be enabled.
+- quickRelease - Whether locks should be released as quickly as possible (before whole commit).
+- propagation - For controlling how nested transactions behave.
+- traceLevel - Transaction trace level.
You can also specify the default values for some of these options in akka.conf. Here they are with their default values:
::
stm {
- max-retries = 1000
- timeout = 10
- write-skew = true
+ fair = on # Should global transactions be fair or non-fair (non fair yield better performance)
+ max-retries = 1000
+ timeout = 5 # Default timeout for blocking transactions and transaction set (in unit defined by
+ # the time-unit property)
+ write-skew = true
blocking-allowed = false
- interruptible = false
- speculative = true
- quick-release = true
- propagation = requires
- trace-level = none
+ interruptible = false
+ speculative = true
+ quick-release = true
+ propagation = "requires"
+ trace-level = "none"
}
Transaction lifecycle listeners
--------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It's possible to have code that will only run on the successful commit of a transaction, or when a transaction aborts. You can do this by adding ``deferred`` or ``compensating`` blocks to a transaction.
@@ -221,7 +227,7 @@ It's possible to have code that will only run on the successful commit of a tran
}.execute();
Blocking transactions
----------------------
+^^^^^^^^^^^^^^^^^^^^^
You can block in a transaction until a condition is met by using an explicit ``retry``. To use ``retry`` you also need to configure the transaction to allow explicit retries.
@@ -232,15 +238,19 @@ Here is an example of using ``retry`` to block until an account has enough money
import akka.stm.*;
public class Transfer {
- public Ref from;
- public Ref to;
- public double amount;
+ private final Ref from;
+ private final Ref to;
+ private final double amount;
- public Transfer(Ref from, Ref to, double amount) {
- this.from = from;
- this.to = to;
- this.amount = amount;
- }
+ public Transfer(Ref from, Ref to, double amount) {
+ this.from = from;
+ this.to = to;
+ this.amount = amount;
+ }
+
+ public Ref getFrom() { return from; }
+ public Ref getTo() { return to; }
+ public double getAmount() { return amount; }
}
.. code-block:: java
@@ -250,6 +260,7 @@ Here is an example of using ``retry`` to block until an account has enough money
import akka.actor.*;
import akka.util.FiniteDuration;
import java.util.concurrent.TimeUnit;
+ import akka.event.EventHandler;
public class Transferer extends UntypedActor {
TransactionFactory txFactory = new TransactionFactoryBuilder()
@@ -261,16 +272,16 @@ Here is an example of using ``retry`` to block until an account has enough money
public void onReceive(Object message) throws Exception {
if (message instanceof Transfer) {
Transfer transfer = (Transfer) message;
- final Ref from = transfer.from;
- final Ref to = transfer.to;
- final double amount = transfer.amount;
+ final Ref from = transfer.getFrom();
+ final Ref to = transfer.getTo();
+ final double amount = transfer.getAmount();
new Atomic(txFactory) {
public Object atomically() {
if (from.get() < amount) {
- System.out.println("Transferer: not enough money - retrying");
+ EventHandler.info(this, "not enough money - retrying");
retry();
}
- System.out.println("Transferer: transferring");
+ EventHandler.info(this, "transferring");
from.set(from.get() - amount);
to.set(to.get() + amount);
return null;
@@ -285,43 +296,51 @@ Here is an example of using ``retry`` to block until an account has enough money
import akka.stm.*;
import akka.actor.*;
- final Ref account1 = new Ref(100.0);
- final Ref account2 = new Ref(100.0);
+ public class Main {
+ public static void main(String...args) throws Exception {
+ final Ref account1 = new Ref(100.0);
+ final Ref account2 = new Ref(100.0);
- ActorRef transferer = Actors.actorOf(Transferer.class).start();
+ ActorRef transferer = Actors.actorOf(Transferer.class).start();
- transferer.sendOneWay(new Transfer(account1, account2, 500.0));
- // Transferer: not enough money - retrying
+ transferer.sendOneWay(new Transfer(account1, account2, 500.0));
+ // Transferer: not enough money - retrying
- new Atomic() {
- public Object atomically() {
- return account1.set(account1.get() + 2000);
- }
- }.execute();
- // Transferer: transferring
+ new Atomic() {
+ public Object atomically() {
+ return account1.set(account1.get() + 2000);
+ }
+ }.execute();
+ // Transferer: transferring
- Double acc1 = new Atomic() {
- public Double atomically() {
- return account1.get();
- }
- }.execute();
+ Thread.sleep(1000);
- Double acc2 = new Atomic() {
- public Double atomically() {
- return account2.get();
- }
- }.execute();
+ Double acc1 = new Atomic() {
+ public Double atomically() {
+ return account1.get();
+ }
+ }.execute();
- System.out.println("Account 1: " + acc1);
- // Account 1: 1600.0
+ Double acc2 = new Atomic() {
+ public Double atomically() {
+ return account2.get();
+ }
+ }.execute();
- System.out.println("Account 2: " + acc2);
- // Account 2: 600.0
- transferer.stop();
+
+ System.out.println("Account 1: " + acc1);
+ // Account 1: 1600.0
+
+ System.out.println("Account 2: " + acc2);
+ // Account 2: 600.0
+
+ transferer.stop();
+ }
+ }
Alternative blocking transactions
----------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can also have two alternative blocking transactions, one of which can succeed first, with ``EitherOrElse``.
@@ -330,24 +349,31 @@ You can also have two alternative blocking transactions, one of which can succee
import akka.stm.*;
public class Branch {
- public Ref left;
- public Ref right;
- public int amount;
+ private final Ref left;
+ private final Ref right;
+ private final double amount;
- public Branch(Ref left, Ref right, int amount) {
- this.left = left;
- this.right = right;
- this.amount = amount;
- }
+ public Branch(Ref left, Ref right, int amount) {
+ this.left = left;
+ this.right = right;
+ this.amount = amount;
+ }
+
+ public Ref getLeft() { return left; }
+
+ public Ref getRight() { return right; }
+
+ public double getAmount() { return amount; }
}
.. code-block:: java
+ import akka.actor.*;
import akka.stm.*;
import static akka.stm.StmUtils.retry;
- import akka.actor.*;
import akka.util.FiniteDuration;
import java.util.concurrent.TimeUnit;
+ import akka.event.EventHandler;
public class Brancher extends UntypedActor {
TransactionFactory txFactory = new TransactionFactoryBuilder()
@@ -359,26 +385,26 @@ You can also have two alternative blocking transactions, one of which can succee
public void onReceive(Object message) throws Exception {
if (message instanceof Branch) {
Branch branch = (Branch) message;
- final Ref left = branch.left;
- final Ref right = branch.right;
- final double amount = branch.amount;
+ final Ref left = branch.getLeft();
+ final Ref right = branch.getRight();
+ final double amount = branch.getAmount();
new Atomic(txFactory) {
public Integer atomically() {
return new EitherOrElse() {
public Integer either() {
if (left.get() < amount) {
- System.out.println("not enough on left - retrying");
+ EventHandler.info(this, "not enough on left - retrying");
retry();
}
- System.out.println("going left");
+ EventHandler.info(this, "going left");
return left.get();
}
public Integer orElse() {
if (right.get() < amount) {
- System.out.println("not enough on right - retrying");
+ EventHandler.info(this, "not enough on right - retrying");
retry();
}
- System.out.println("going right");
+ EventHandler.info(this, "going right");
return right.get();
}
}.execute();
@@ -393,32 +419,40 @@ You can also have two alternative blocking transactions, one of which can succee
import akka.stm.*;
import akka.actor.*;
- final Ref left = new Ref(100);
- final Ref right = new Ref(100);
+ public class Main2 {
+ public static void main(String...args) throws Exception {
+ final Ref left = new Ref(100);
+ final Ref right = new Ref(100);
- ActorRef brancher = Actors.actorOf(Brancher.class).start();
+ ActorRef brancher = Actors.actorOf(Brancher.class).start();
- brancher.sendOneWay(new Branch(left, right, 500));
- // not enough on left - retrying
- // not enough on right - retrying
+ brancher.sendOneWay(new Branch(left, right, 500));
+ // not enough on left - retrying
+ // not enough on right - retrying
- new Atomic() {
- public Object atomically() {
- return right.set(right.get() + 1000);
- }
- }.execute();
- // going right
+ Thread.sleep(1000);
- brancher.stop();
+ new Atomic() {
+ public Object atomically() {
+ return right.set(right.get() + 1000);
+ }
+ }.execute();
+ // going right
+
+
+
+ brancher.stop();
+ }
+ }
-----
Transactional datastructures
-============================
+----------------------------
Akka provides two datastructures that are managed by the STM.
-* TransactionalMap
-* TransactionalVector
+
+- TransactionalMap
+- TransactionalVector
TransactionalMap and TransactionalVector look like regular mutable datastructures, they even implement the standard Scala 'Map' and 'RandomAccessSeq' interfaces, but they are implemented using persistent datastructures and managed references under the hood. Therefore they are safe to use in a concurrent environment. Underlying TransactionalMap is HashMap, an immutable Map but with near constant time access and modification operations. Similarly TransactionalVector uses a persistent Vector. See the Persistent Datastructures section below for more details.
@@ -477,25 +511,24 @@ Here is an example of creating and accessing a TransactionalVector:
}
}.execute();
-----
Persistent datastructures
-=========================
+-------------------------
Akka's STM should only be used with immutable data. This can be costly if you have large datastructures and are using a naive copy-on-write. In order to make working with immutable datastructures fast enough Scala provides what are called Persistent Datastructures. There are currently two different ones:
-* HashMap (`scaladoc `_)
-* Vector (`scaladoc `_)
+
+- HashMap (`scaladoc `__)
+- Vector (`scaladoc `__)
They are immutable and each update creates a completely new version but they are using clever structural sharing in order to make them almost as fast, for both read and update, as regular mutable datastructures.
This illustration is taken from Rich Hickey's presentation. Copyright Rich Hickey 2009.
-``_
+.. image:: ../images/clojure-trees.png
-----
JTA integration
-===============
+---------------
The STM has JTA (Java Transaction API) integration. This means that it will, if enabled, hook in to JTA and start a JTA transaction when the STM transaction is started. It will also rollback the STM transaction if the JTA transaction has failed and vice versa. This does not mean that the STM is made durable, if you need that you should use one of the `persistence modules `_. It simply means that the STM will participate and interact with and external JTA provider, for example send a message using JMS atomically within an STM transaction, or use Hibernate to persist STM managed data etc.
@@ -512,11 +545,13 @@ You can enable JTA support in the 'stm' section in the config:
You also have to configure which JTA provider to use etc in the 'jta' config section:
-``_
- jta {
- provider = "from-jndi" # Options: "from-jndi" (means that Akka will try to detect a TransactionManager in the JNDI)
- # "atomikos" (means that Akka will use the Atomikos based JTA impl in 'akka-jta',
- # e.g. you need the akka-jta JARs on classpath).
- timeout = 60
- }
-``_
+::
+
+ jta {
+ provider = "from-jndi" # Options: "from-jndi" (means that Akka will try to detect a TransactionManager in the JNDI)
+ # "atomikos" (means that Akka will use the Atomikos based JTA impl in 'akka-jta',
+ # e.g. you need the akka-jta JARs on classpath).
+ timeout = 60
+ }
+
+
diff --git a/akka-docs/pending/transactors-java.rst b/akka-docs/java/transactors.rst
similarity index 83%
rename from akka-docs/pending/transactors-java.rst
rename to akka-docs/java/transactors.rst
index 6547063703..b724ef89b6 100644
--- a/akka-docs/pending/transactors-java.rst
+++ b/akka-docs/java/transactors.rst
@@ -1,10 +1,16 @@
-**Transactors (Java)**
-============================================================
+.. _transactors-java:
+
+Transactors (Java)
+==================
+
+.. sidebar:: Contents
+
+ .. contents:: :local:
Module stability: **SOLID**
Why Transactors?
-================
+----------------
Actors are excellent for solving problems where you have many independent processes that can work in isolation and only interact with other Actors through message passing. This model fits many problems. But the actor model is unfortunately a terrible model for implementing truly shared state. E.g. when you need to have consensus and a stable view of state across many components. The classic example is the bank account where clients can deposit and withdraw, in which each operation needs to be atomic. For detailed discussion on the topic see `this JavaOne presentation `_.
@@ -15,21 +21,21 @@ Akka's Transactors combine Actors and STM to provide the best of the Actor model
If you need Durability then you should not use one of the in-memory data structures but one of the persistent ones.
Generally, the STM is not needed very often when working with Akka. Some use-cases (that we can think of) are:
-# When you really need composable message flows across many actors updating their **internal local** state but need them to do that atomically in one big transaction. Might not often, but when you do need this then you are screwed without it.
-# When you want to share a datastructure across actors.
-# When you need to use the persistence modules.
+
+- When you really need composable message flows across many actors updating their **internal local** state but need them to do that atomically in one big transaction. Might not often, but when you do need this then you are screwed without it.
+- When you want to share a datastructure across actors.
+- When you need to use the persistence modules.
Actors and STM
---------------
+^^^^^^^^^^^^^^
You can combine Actors and STM in several ways. An Actor may use STM internally so that particular changes are guaranteed to be atomic. Actors may also share transactional datastructures as the STM provides safe shared state across threads.
It's also possible to coordinate transactions across Actors or threads so that either the transactions in a set all commit successfully or they all fail. This is the focus of Transactors and the explicit support for coordinated transactions in this section.
-----
Coordinated transactions
-========================
+------------------------
Akka provides an explicit mechanism for coordinating transactions across actors. Under the hood it uses a ``CountDownCommitBarrier``, similar to a CountDownLatch.
@@ -40,9 +46,11 @@ Here is an example of coordinating two simple counter UntypedActors so that they
import akka.actor.ActorRef;
public class Increment {
- private ActorRef friend = null;
+ private final ActorRef friend;
- public Increment() {}
+ public Increment() {
+ this.friend = null;
+ }
public Increment(ActorRef friend) {
this.friend = friend;
@@ -59,9 +67,7 @@ Here is an example of coordinating two simple counter UntypedActors so that they
.. code-block:: java
- import akka.actor.ActorRef;
import akka.actor.UntypedActor;
- import static akka.actor.Actors.*;
import akka.stm.Ref;
import akka.transactor.Atomically;
import akka.transactor.Coordinated;
@@ -88,11 +94,8 @@ Here is an example of coordinating two simple counter UntypedActors so that they
}
});
}
- } else if (incoming instanceof String) {
- String message = (String) incoming;
- if (message.equals("GetCount")) {
- getContext().replyUnsafe(count.get());
- }
+ } else if (incoming.equals("GetCount")) {
+ getContext().replyUnsafe(count.get());
}
}
}
@@ -104,7 +107,7 @@ Here is an example of coordinating two simple counter UntypedActors so that they
counter1.sendOneWay(new Coordinated(new Increment(counter2)));
-To start a new coordinated transaction set that you will also participate in, just create a ``Coordinated`` object:
+To start a new coordinated transaction that you will also participate in, just create a ``Coordinated`` object:
.. code-block:: java
@@ -116,7 +119,7 @@ To start a coordinated transaction that you won't participate in yourself you ca
actor.sendOneWay(new Coordinated(new Message()));
-To include another actor in the same coordinated transaction set that you've created or received, use the ``coordinate`` method on that object. This will increment the number of parties involved by one and create a new ``Coordinated`` object to be sent.
+To include another actor in the same coordinated transaction that you've created or received, use the ``coordinate`` method on that object. This will increment the number of parties involved by one and create a new ``Coordinated`` object to be sent.
.. code-block:: java
@@ -134,10 +137,9 @@ To enter the coordinated transaction use the atomic method of the coordinated ob
The coordinated transaction will wait for the other transactions before committing. If any of the coordinated transactions fail then they all fail.
-----
UntypedTransactor
-=================
+-----------------
UntypedTransactors are untyped actors that provide a general pattern for coordinating transactions, using the explicit coordination described above.
@@ -146,10 +148,12 @@ Here's an example of a simple untyped transactor that will join a coordinated tr
.. code-block:: java
import akka.transactor.UntypedTransactor;
+ import akka.stm.Ref;
public class Counter extends UntypedTransactor {
Ref count = new Ref(0);
+ @Override
public void atomically(Object message) {
if (message instanceof Increment) {
count.set(count.get() + 1);
@@ -174,7 +178,8 @@ Example of coordinating an increment, similar to the explicitly coordinated exam
public class Counter extends UntypedTransactor {
Ref count = new Ref(0);
- @Override public Set coordinate(Object message) {
+ @Override
+ public Set coordinate(Object message) {
if (message instanceof Increment) {
Increment increment = (Increment) message;
if (increment.hasFriend())
@@ -183,6 +188,7 @@ Example of coordinating an increment, similar to the explicitly coordinated exam
return nobody();
}
+ @Override
public void atomically(Object message) {
if (message instanceof Increment) {
count.set(count.get() + 1);
@@ -190,14 +196,13 @@ Example of coordinating an increment, similar to the explicitly coordinated exam
}
}
-To exeucte directly before or after the coordinated transaction, override the ``before`` and ``after`` methods. These methods also expect partial functions like the receive method. They do not execute within the transaction.
+To execute directly before or after the coordinated transaction, override the ``before`` and ``after`` methods. They do not execute within the transaction.
To completely bypass coordinated transactions override the ``normally`` method. Any message matched by ``normally`` will not be matched by the other methods, and will not be involved in coordinated transactions. In this method you can implement normal actor behavior, or use the normal STM atomic for local transactions.
-----
Coordinating Typed Actors
-=========================
+-------------------------
It's also possible to use coordinated transactions with typed actors. You can explicitly pass around ``Coordinated`` objects, or use built-in support with the ``@Coordinated`` annotation and the ``Coordination.coordinate`` method.
@@ -249,17 +254,18 @@ Here's an example of using ``@Coordinated`` with a TypedActor to coordinate incr
}
}
-``_
-Counter counter1 = (Counter) TypedActor.newInstance(Counter.class, CounterImpl.class);
-Counter counter2 = (Counter) TypedActor.newInstance(Counter.class, CounterImpl.class);
+.. code-block:: java
-Coordination.coordinate(true, new Atomically() {
+ Counter counter1 = (Counter) TypedActor.newInstance(Counter.class, CounterImpl.class);
+ Counter counter2 = (Counter) TypedActor.newInstance(Counter.class, CounterImpl.class);
+
+ Coordination.coordinate(true, new Atomically() {
public void atomically() {
- counter1.increment();
- counter2.increment();
+ counter1.increment();
+ counter2.increment();
}
-});
+ });
+
+ TypedActor.stop(counter1);
+ TypedActor.stop(counter2);
-TypedActor.stop(counter1);
-TypedActor.stop(counter2);
-``_
diff --git a/akka-docs/pending/typed-actors-java.rst b/akka-docs/java/typed-actors.rst
similarity index 97%
rename from akka-docs/pending/typed-actors-java.rst
rename to akka-docs/java/typed-actors.rst
index 2322698ed1..acd99b7fcf 100644
--- a/akka-docs/pending/typed-actors-java.rst
+++ b/akka-docs/java/typed-actors.rst
@@ -1,6 +1,10 @@
Typed Actors (Java)
===================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
The Typed Actors are implemented through `Typed Actors `_. It uses AOP through `AspectWerkz `_ to turn regular POJOs into asynchronous non-blocking Actors with semantics of the Actor Model. E.g. each message dispatch is turned into a message that is put on a queue to be processed by the Typed Actor sequentially one by one.
@@ -100,7 +104,7 @@ Methods that return void are turned into ‘fire-and-forget’ semantics by asyn
Request-reply message send
^^^^^^^^^^^^^^^^^^^^^^^^^^
-Methods that return something (e.g. non-void methods) are turned into ‘send-and-recieve-eventually’ semantics by asynchronously firing off the message and wait on the reply using a Future.
+Methods that return something (e.g. non-void methods) are turned into ‘send-and-receive-eventually’ semantics by asynchronously firing off the message and wait on the reply using a Future.
.. code-block:: java
@@ -118,7 +122,7 @@ The same holds for the 'request-reply-with-future' described below.
Request-reply-with-future message send
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Methods that return a 'akka.dispatch.Future' are turned into ‘send-and-recieve-with-future’ semantics by asynchronously firing off the message and returns immediately with a Future. You need to use the 'future(...)' method in the TypedActor base class to resolve the Future that the client code is waiting on.
+Methods that return a 'akka.dispatch.Future' are turned into ‘send-and-receive-with-future’ semantics by asynchronously firing off the message and returns immediately with a Future. You need to use the 'future(...)' method in the TypedActor base class to resolve the Future that the client code is waiting on.
Here is an example:
@@ -171,7 +175,7 @@ Here is an example how you can use it to in a 'void' (e.g. fire-forget) method t
}
}
-If the sender, sender future etc. is not available, then these methods will return 'null' so you should have a way of dealing with scenario.
+If the sender, sender future etc. is not available, then these methods will return 'null' so you should have a way of dealing with that scenario.
Messages and immutability
-------------------------
diff --git a/akka-docs/pending/untyped-actors-java.rst b/akka-docs/java/untyped-actors.rst
similarity index 92%
rename from akka-docs/pending/untyped-actors-java.rst
rename to akka-docs/java/untyped-actors.rst
index 760b5fd324..5a29d13ae5 100644
--- a/akka-docs/pending/untyped-actors-java.rst
+++ b/akka-docs/java/untyped-actors.rst
@@ -1,7 +1,9 @@
Actors (Java)
=============
-=
+.. sidebar:: Contents
+
+ .. contents:: :local:
Module stability: **SOLID**
@@ -16,11 +18,15 @@ Here is an example:
.. code-block:: java
+ import akka.actor.UntypedActor;
+ import akka.event.EventHandler;
+
public class SampleUntypedActor extends UntypedActor {
public void onReceive(Object message) throws Exception {
if (message instanceof String)
- EventHandler.info(this, String.format("Received String message: %s", message));
+ EventHandler.info(this, String.format("Received String message: %s",
+ message));
else
throw new IllegalArgumentException("Unknown message: " + message);
}
@@ -51,7 +57,7 @@ You can also create & start the actor in one statement:
ActorRef myActor = actorOf(SampleUntypedActor.class).start();
-The call to 'actorOf' returns an instance of 'ActorRef'. This is a handle to the 'UntypedActor' instance which you can use to interact with the Actor, like send messages to it etc. more on this shortly. The 'ActorRef' is immutble and has a one to one relationship with the Actor it represents. The 'ActorRef' is also serializable and network-aware. This means that you can serialize it, send it over the wire and use it on a remote host and it will still be representing the same Actor on the original node, across the network.
+The call to 'actorOf' returns an instance of 'ActorRef'. This is a handle to the 'UntypedActor' instance which you can use to interact with the Actor, like send messages to it etc. more on this shortly. The 'ActorRef' is immutable and has a one to one relationship with the Actor it represents. The 'ActorRef' is also serializable and network-aware. This means that you can serialize it, send it over the wire and use it on a remote host and it will still be representing the same Actor on the original node, across the network.
Creating Actors with non-default constructor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +109,7 @@ Messages are sent to an Actor through one of the 'send' methods.
* 'sendRequestReply' means “send-and-reply-eventually”, e.g. send a message asynchronously and wait for a reply through a Future. Here you can specify a timeout. Using timeouts is very important. If no timeout is specified then the actor’s default timeout (set by the 'getContext().setTimeout(..)' method in the 'ActorRef') is used. This method throws an 'ActorTimeoutException' if the call timed out.
* 'sendRequestReplyFuture' sends a message asynchronously and returns a 'Future'.
-In all these methods you have the option of passing along your 'ActorRef' context variable. Make it a practive of doing so because it will allow the receiver actors to be able to respond to your message, since the sender reference is sent along with the message.
+In all these methods you have the option of passing along your 'ActorRef' context variable. Make it a practice of doing so because it will allow the receiver actors to be able to respond to your message, since the sender reference is sent along with the message.
Fire-forget
^^^^^^^^^^^
@@ -138,7 +144,7 @@ Here are some examples:
.. code-block:: java
- UnypedActorRef actorRef = ...
+ UntypedActorRef actorRef = ...
try {
Object result = actorRef.sendRequestReply("Hello", getContext(), 1000);
@@ -256,7 +262,7 @@ The 'replyUnsafe' method throws an 'IllegalStateException' if unable to determin
Reply using the sender reference
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-If the sender reference (the sender's 'ActorRef') is passed into one ofe the 'send*' methods it will be implicitly passed along together with the message and will be available in the 'Option getSender()' method on the 'ActorRef. This means that you can use this field to send a message back to the sender.
+If the sender reference (the sender's 'ActorRef') is passed into one of the 'send*' methods it will be implicitly passed along together with the message and will be available in the 'Option getSender()' method on the 'ActorRef. This means that you can use this field to send a message back to the sender.
On this 'Option' you can invoke 'boolean isDefined()' or 'boolean isEmpty()' to check if the sender is available or not, and if it is call 'get()' to get the reference. It's important to know that 'getSender().get()' will throw an exception if there is no sender in scope. The same pattern holds for using the 'getSenderFuture()' in the section below.
@@ -267,7 +273,7 @@ On this 'Option' you can invoke 'boolean isDefined()' or 'boolean isEmpty()' to
String msg = (String)message;
if (msg.equals("Hello")) {
// Reply to original sender of message using the sender reference
- // also passing along my own refererence (the context)
+ // also passing along my own reference (the context)
if (getContext().getSender().isDefined)
getContext().getSender().get().sendOneWay(msg + " from " + getContext().getUuid(), getContext());
}
@@ -279,7 +285,7 @@ Reply using the sender future
If a message was sent with the 'sendRequestReply' or 'sendRequestReplyFuture' methods, which both implements request-reply semantics using Future's, then you either have the option of replying using the 'reply' method as above. This method will then resolve the Future. But you can also get a reference to the Future directly and resolve it yourself or if you would like to store it away to resolve it later, or pass it on to some other Actor to resolve it.
-The reference to the Future resides in the 'ActorRef' instance and can be retreived using 'Option getSenderFuture()'.
+The reference to the Future resides in the 'ActorRef' instance and can be retrieved using 'Option getSenderFuture()'.
CompletableFuture is a future with methods for 'completing the future:
* completeWithResult(..)
@@ -337,7 +343,7 @@ Actors are started by invoking the ‘start’ method.
ActorRef actor = actorOf(SampleUntypedActor.class);
myActor.start();
-You can create and start the Actor in a oneliner like this:
+You can create and start the Actor in a one liner like this:
.. code-block:: java
@@ -409,8 +415,9 @@ Actor life-cycle
The actor has a well-defined non-circular life-cycle.
-``_
-NEW (newly created actor) - can't receive messages (yet)
- => STARTED (when 'start' is invoked) - can receive messages
- => SHUT DOWN (when 'exit' or 'stop' is invoked) - can't do anything
-``_
+::
+
+ NEW (newly created actor) - can't receive messages (yet)
+ => STARTED (when 'start' is invoked) - can receive messages
+ => SHUT DOWN (when 'exit' or 'stop' is invoked) - can't do anything
+
diff --git a/akka-docs/pending/companies-using-akka.rst b/akka-docs/pending/companies-using-akka.rst
index 3832adab1b..aae679be9d 100644
--- a/akka-docs/pending/companies-using-akka.rst
+++ b/akka-docs/pending/companies-using-akka.rst
@@ -41,7 +41,7 @@ SVT (Swedish Television)
*Our system is highly asynchronous so the actor style of doing things is a perfect fit. I don’t know about how you feel about concurrency in a big system, but rolling your own abstractions is not a very easy thing to do. When using Akka you can almost forget about all that. Synchronizing between threads, locking and protecting access to state etc. Akka is not just about actors, but that’s one of the most pleasurable things to work with. It’s easy to add new ones and it’s easy to design with actors. You can fire up work actors tied to a specific dispatcher etc. I could make the list of benefits much longer, but I’m at work right now. I suggest you try it out and see how it fits your requirements.*
-*We saw a perfect businness reson for using Akka. It lets you concentrate on the business logic instead of the low level things. It’s easy to teach others and the business intent is clear just by reading the code. We didn’t chose Akka just for fun. It’s a business critical application that’s used in broadcasting. Even live broadcasting. We wouldn’t have been where we are today in such a short time without using Akka. We’re two developers that have done great things in such a short amount of time and part of this is due to Akka. As I said, it lets us focus on the business logic instead of low level things such as concurrency, locking, performence etc."*
+*We saw a perfect business reason for using Akka. It lets you concentrate on the business logic instead of the low level things. It’s easy to teach others and the business intent is clear just by reading the code. We didn’t chose Akka just for fun. It’s a business critical application that’s used in broadcasting. Even live broadcasting. We wouldn’t have been where we are today in such a short time without using Akka. We’re two developers that have done great things in such a short amount of time and part of this is due to Akka. As I said, it lets us focus on the business logic instead of low level things such as concurrency, locking, performance etc."*
Tapad
-----
@@ -107,7 +107,7 @@ LShift
* *"Diffa is an open source data analysis tool that automatically establishes data differences between two or more real-time systems.*
* Diffa will help you compare local or distributed systems for data consistency, without having to stop them running or implement manual cross-system comparisons. The interface provides you with simple visual summary of any consistency breaks and tools to investigate the issues.*
-* Diffa is the ideal tool to use to investigate where or when inconsistencies are occuring, or simply to provide confidence that your systems are running in perfect sync. It can be used operationally as an early warning system, in deployment for release verification, or in development with other enterprise diagnosis tools to help troubleshoot faults."*
+* Diffa is the ideal tool to use to investigate where or when inconsistencies are occurring, or simply to provide confidence that your systems are running in perfect sync. It can be used operationally as an early warning system, in deployment for release verification, or in development with other enterprise diagnosis tools to help troubleshoot faults."*
` `_
diff --git a/akka-docs/pending/fault-tolerance-java.rst b/akka-docs/pending/fault-tolerance-java.rst
index 18cbb63e9e..96190c7b8e 100644
--- a/akka-docs/pending/fault-tolerance-java.rst
+++ b/akka-docs/pending/fault-tolerance-java.rst
@@ -125,7 +125,7 @@ The Actor’s supervision can be declaratively defined by creating a ‘Supervis
Supervisors created like this are implicitly instantiated and started.
-To cofigure a handler function for when the actor underlying the supervisor recieves a MaximumNumberOfRestartsWithinTimeRangeReached message, you can specify
+To configure a handler function for when the actor underlying the supervisor receives a MaximumNumberOfRestartsWithinTimeRangeReached message, you can specify
a Procedure2 when creating the SupervisorConfig. This handler will be called with the ActorRef of the supervisor and the
MaximumNumberOfRestartsWithinTimeRangeReached message.
@@ -213,7 +213,7 @@ Here is an example:
true)
}));
-Programmatical linking and supervision of Untyped Actors
+Programmatic linking and supervision of Untyped Actors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Untyped Actors can at runtime create, spawn, link and supervise other actors. Linking and unlinking is done using one of the 'link' and 'unlink' methods available in the 'ActorRef' (therefore prefixed with getContext() in these examples).
@@ -459,10 +459,10 @@ In the supervised TypedActor you can override the ‘preRestart’ and ‘postRe
}
}
-Programatical linking and supervision of TypedActors
+Programatic linking and supervision of TypedActors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-TypedActors can be linked an unlinked just like UntypedActors:
+TypedActors can be linked and unlinked just like UntypedActors:
.. code-block:: java
diff --git a/akka-docs/pending/fault-tolerance-scala.rst b/akka-docs/pending/fault-tolerance-scala.rst
index 5e02cf232a..84cc48d549 100644
--- a/akka-docs/pending/fault-tolerance-scala.rst
+++ b/akka-docs/pending/fault-tolerance-scala.rst
@@ -121,7 +121,7 @@ The Actor's supervision can be declaratively defined by creating a "Supervisor'
Supervisors created like this are implicitly instantiated and started.
-To cofigure a handler function for when the actor underlying the supervisor recieves a MaximumNumberOfRestartsWithinTimeRangeReached message, you can specify a function of type
+To configure a handler function for when the actor underlying the supervisor receives a MaximumNumberOfRestartsWithinTimeRangeReached message, you can specify a function of type
(ActorRef, MaximumNumberOfRestartsWithinTimeRangeReached) => Unit when creating the SupervisorConfig. This handler will be called with the ActorRef of the supervisor and the
MaximumNumberOfRestartsWithinTimeRangeReached message.
@@ -194,7 +194,7 @@ Here is an example:
**true**)
:: Nil))
-Programmatical linking and supervision of Actors
+Programmatic linking and supervision of Actors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Actors can at runtime create, spawn, link and supervise other actors. Linking and unlinking is done using one of the 'link' and 'unlink' methods available in the 'ActorRef' (therefore prefixed with 'self' in these examples).
@@ -316,7 +316,7 @@ Supervised actors have the option to reply to the initial sender within preResta
self.reply_?(reason.getMessage)
}
- override def postStop {
+ override def postStop() {
self.reply_?("stopped by supervisor")
}
}
@@ -411,10 +411,10 @@ Then you can retrieve the Typed Actor as follows:
Restart callbacks
^^^^^^^^^^^^^^^^^
-Programatical linking and supervision of TypedActors
+Programatic linking and supervision of TypedActors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-TypedActors can be linked an unlinked just like actors - in fact the linking is done on the underlying actor:
+TypedActors can be linked and unlinked just like actors - in fact the linking is done on the underlying actor:
.. code-block:: scala
diff --git a/akka-docs/pending/futures-scala.rst b/akka-docs/pending/futures-scala.rst
index 3426ce0ff6..f03990a1cf 100644
--- a/akka-docs/pending/futures-scala.rst
+++ b/akka-docs/pending/futures-scala.rst
@@ -11,7 +11,7 @@ Use with Actors
There are generally two ways of getting a reply from an ``Actor``: the first is by a sent message (``actor ! msg``), which only works if the original sender was an ``Actor``) and the second is through a ``Future``.
-Using an ``Actor``\'s ``!!!`` method to send a message will return a Future. To wait for and retreive the actual result the simplest method is:
+Using an ``Actor``\'s ``!!!`` method to send a message will return a Future. To wait for and retrieve the actual result the simplest method is:
.. code-block:: scala
@@ -97,7 +97,7 @@ If we do the opposite:
Our little string has been processed long before our 1 second sleep has finished. Because of this, the dispatcher has moved onto other messages that need processing and can no longer calculate the length of the string for us, instead it gets calculated in the current thread just as if we weren't using a Future.
-Normally this works quite well for us as it means there is very little overhead to running a quick Function. If there is a possiblity of the Function taking a non-trivial amount of time to process it might be better to have this done concurrently, and for that we use 'flatMap':
+Normally this works quite well for us as it means there is very little overhead to running a quick Function. If there is a possibility of the Function taking a non-trivial amount of time to process it might be better to have this done concurrently, and for that we use 'flatMap':
.. code-block:: scala
@@ -150,7 +150,7 @@ The example for comprehension above is an example of composing Futures. A common
Here we have 2 actors processing a single message each. In the for comprehension we need to add the expected types in order to work with the results. Once the 2 results are available, they are being added together and sent to a third actor, which replies with a String, which we assign to 'result'.
-This is fine when dealing with a known amount of Actors, but can grow unwieldly if we have more then a handful. The 'sequence' and 'traverse' helper methods can make it easier to handle more complex use cases. Both of these methods are ways of turning a Traversable[Future[A]] into a Future[Traversable[A]]. For example:
+This is fine when dealing with a known amount of Actors, but can grow unwieldy if we have more then a handful. The 'sequence' and 'traverse' helper methods can make it easier to handle more complex use cases. Both of these methods are ways of turning a Traversable[Future[A]] into a Future[Traversable[A]]. For example:
.. code-block:: scala
diff --git a/akka-docs/pending/getting-started.rst b/akka-docs/pending/getting-started.rst
index 8f86f5cfca..d76db9b299 100644
--- a/akka-docs/pending/getting-started.rst
+++ b/akka-docs/pending/getting-started.rst
@@ -18,7 +18,7 @@ Download the release you need (Akka core or Akka Modules) from ` `_ annotations (such as ‘@Inject’ etc.).
+All Typed Actors support dependency injection using `Guice `_ annotations (such as ‘@Inject’ etc.).
The ‘TypedActorManager’ class understands Guice and will do the wiring for you.
External Guice modules
diff --git a/akka-docs/pending/http.rst b/akka-docs/pending/http.rst
index 739f443c1d..9de34d05e7 100644
--- a/akka-docs/pending/http.rst
+++ b/akka-docs/pending/http.rst
@@ -138,12 +138,12 @@ If you want to use akka-camel or any other modules that have their own "Bootable
Java API: Typed Actors
----------------------
-`Sample module for REST services with Actors in Java `_
+`Sample module for REST services with Actors in Java `_
Scala API: Actors
-----------------
-`Sample module for REST services with Actors in Scala `_
+`Sample module for REST services with Actors in Scala `_
Using Akka with the Pinky REST/MVC framework
--------------------------------------------
@@ -179,7 +179,7 @@ Endpoints are actors that handle request messages. Minimally there must be an in
Preparations
^^^^^^^^^^^^
-In order to use Mist you have to register the MistServlet in *web.xml* or do the analogous for the embedded server if running in Akka Micrkernel:
+In order to use Mist you have to register the MistServlet in *web.xml* or do the analogous for the embedded server if running in Akka Microkernel:
.. code-block:: xml
@@ -269,7 +269,7 @@ Finally, bind the *handleHttpRequest* function of the *Endpoint* trait to the ac
//
// this is where you want attach your endpoint hooks
//
- override def preStart = {
+ override def preStart() = {
//
// we expect there to be one root and that it's already been started up
// obviously there are plenty of other ways to obtaining this actor
@@ -397,7 +397,7 @@ As noted above, hook functions are non-exclusive. This means multiple actors can
//
// this is where you want attach your endpoint hooks
//
- override def preStart = {
+ override def preStart() = {
//
// we expect there to be one root and that it's already been started up
// obviously there are plenty of other ways to obtaining this actor
@@ -419,7 +419,7 @@ As noted above, hook functions are non-exclusive. This means multiple actors can
def receive = handleHttpRequest
//
- // this guy completes requests after other actions have occured
+ // this guy completes requests after other actions have occurred
//
lazy val complete = actorOf[ActionCompleteActor].start()
}
diff --git a/akka-docs/pending/issue-tracking.rst b/akka-docs/pending/issue-tracking.rst
index fcff2e2c94..fa81a4d254 100644
--- a/akka-docs/pending/issue-tracking.rst
+++ b/akka-docs/pending/issue-tracking.rst
@@ -7,6 +7,8 @@ Browsing
--------
You can find the Akka tickets here: ``_
+You can find the Akka Modules tickets here: ``_
+
The roadmap for each milestone is here: ``_
Creating tickets
@@ -16,8 +18,16 @@ In order to create tickets you need to do the following:
# Register here: ``_
# Log in
+
+For Akka tickets:
+
# Create the ticket: ``_
+
+For Akka Modules tickets:
+
+# Create the ticket: ``_
+
Thanks a lot for reporting bugs and suggesting features.
Failing test
diff --git a/akka-docs/pending/release-notes.rst b/akka-docs/pending/release-notes.rst
index 2000b5a1d6..692e7ce244 100644
--- a/akka-docs/pending/release-notes.rst
+++ b/akka-docs/pending/release-notes.rst
@@ -315,7 +315,7 @@ Release 0.10 - Aug 21 2010
||< **ADD** ||< Added isDefinedAt method to Actor for checking if it can receive a certain message ||< Jonas Bonér ||
||< **ADD** ||< Added caching of Active Object generated class bytes, huge perf improvement ||< Jonas Bonér ||
||< **ADD** ||< Added RemoteClient Listener API ||< Jonas Bonér ||
-||< **ADD** ||< Added methods to retreive children from a Supervisor ||< Jonas Bonér ||
+||< **ADD** ||< Added methods to retrieve children from a Supervisor ||< Jonas Bonér ||
||< **ADD** ||< Rewritten Supervisor to become more clear and "correct" ||< Jonas Bonér ||
||< **ADD** ||< Added options to configure a blocking mailbox with custom capacity ||< Jonas Bonér ||
||< **ADD** ||< Added RemoteClient reconnection time window configuration option ||< Jonas Bonér ||
diff --git a/akka-docs/pending/routing-scala.rst b/akka-docs/pending/routing-scala.rst
index 4cb825219e..3885290ccb 100644
--- a/akka-docs/pending/routing-scala.rst
+++ b/akka-docs/pending/routing-scala.rst
@@ -219,18 +219,16 @@ Examples
with SmallestMailboxSelector
with BasicNoBackoffFilter
{
- def factory = actorOf(new Actor {def receive = {case n:Int =>
- Thread.sleep(n)
- counter.incrementAndGet
- latch.countDown()}})
-
+ def receive = _route
def lowerBound = 2
def upperBound = 4
def rampupRate = 0.1
def partialFill = true
def selectionCount = 1
- def instance = factory
- def receive = _route
+ def instance = actorOf(new Actor {def receive = {case n:Int =>
+ Thread.sleep(n)
+ counter.incrementAndGet
+ latch.countDown()}})
}
.. code-block:: scala
@@ -243,11 +241,7 @@ Examples
with RunningMeanBackoff
with BasicRampup
{
-
- def factory = actorOf(new Actor {def receive = {case n:Int =>
- Thread.sleep(n)
- latch.countDown()}})
-
+ def receive = _route
def lowerBound = 1
def upperBound = 5
def pressureThreshold = 1
@@ -256,8 +250,9 @@ Examples
def rampupRate = 0.1
def backoffRate = 0.50
def backoffThreshold = 0.50
- def instance = factory
- def receive = _route
+ def instance = actorOf(new Actor {def receive = {case n:Int =>
+ Thread.sleep(n)
+ latch.countDown()}})
}
Taken from the unit test `spec `_.
diff --git a/akka-docs/pending/security.rst b/akka-docs/pending/security.rst
index 3600c21285..cae23fbdd5 100644
--- a/akka-docs/pending/security.rst
+++ b/akka-docs/pending/security.rst
@@ -89,7 +89,7 @@ How does it work (at least for REST actors)?
# The browser will send the *service ticket* to the web application encoded in the header value of the *Authorization*header
# The web application must validate the ticket based on a shared secret between the web application and the kerberos server. As a result the web application will know the name of the user
-To activate the kerberos/SPNEGO authentication for your REST actor you need to enable the kerberos/SPNGEOauthentication actor in the akka.conf like this:
+To activate the kerberos/SPNEGO authentication for your REST actor you need to enable the kerberos/SPNEGOauthentication actor in the akka.conf like this:
.. code-block:: ruby
diff --git a/akka-docs/pending/sponsors.rst b/akka-docs/pending/sponsors.rst
index 65faac6794..88d35f1f0a 100644
--- a/akka-docs/pending/sponsors.rst
+++ b/akka-docs/pending/sponsors.rst
@@ -4,7 +4,7 @@
Scalable Solutions
==================
-Scalable Solutions AB is commercial entity behind Akka, providing support, consulting and training around Akka.
+Scalable Solutions AB is the commercial entity behind Akka, providing support, consulting and training around Akka.
``_
YourKit
diff --git a/akka-docs/pending/stm.rst b/akka-docs/pending/stm.rst
index c84ca4e6bb..54984eecf8 100644
--- a/akka-docs/pending/stm.rst
+++ b/akka-docs/pending/stm.rst
@@ -1,27 +1,29 @@
Akka STM
+========
The Akka Software Transactional Memory implementation
**Read consistency**
^^^^^^^^^^^^^^^^^^^^
-Read consistency is that all value
+Read consistency is that all value TODO???
-**Read concistency and MVCC**
+**Read consistency and MVCC**
*****************************
-A lot of STM (like the Clojure STM) implementations are Multi Version Concurrency Control Based (MVCC) based (TL2 of david dice could be seen as MVCC).
+A lot of STM (like the Clojure STM) implementations are Multi Version Concurrency Control (MVCC) based (TL2 of david dice could be seen as MVCC).
To provide read consistency, every ref is augmented with a version field (a long). There also is a logical clock (an AtomicLong for instance) that is incremented every time a transaction does a commit (there are some optimizations) and on all refs written, the version of the ref is updated to this new clock value.
If a transaction begins, it reads the current version of the clock and makes sure that the version of the refs it reads, are equal or lower than the version of the transaction. If the transaction encounters a ref with a higher value, the transaction is aborted and retried.
MVCC STM’s are relatively simple to write and have some very nice properties:
-# readers don’t block writers
-# writers don’t block readers
-# persistent data-structures are very easy to write since a log can be added to each ref containing older versions of the data,
-The problem with MVCC however is that the central clock forms a contention point that makes independent transactional data-structures not linearly scalable. todo: give example of scalability with MVCC.
+- readers don’t block writers
+- writers don’t block readers
+- persistent data-structures are very easy to write since a log can be added to each ref containing older versions of the data
+
+The problem with MVCC however is that the central clock forms a contention point that makes independent transactional data-structures not linearly scalable. TODO: give example of scalability with MVCC.
So even if you have 2 Threads having their private transactional Ref (so there is no visible contention), underwater the transaction still are going to contend for the clock.
@@ -35,26 +37,29 @@ It uses 2 different mechanisms:
2) For longer transactions it uses semi visible reads. Every time a read is done, the surplus of readers is incremented and stored in the ref. Once the transaction aborts or commits, the surplus is lowered again. If a transaction does an update, and sees that there is a surplus of readers, it increments a conflict counter. This conflict counter is checked every time a transaction reads a new ref. If it hasn’t changed, no full conflict scan is needed. If it has changed, a full conflict scan is required. If a conflict is detected, the transaction is aborted and retried. This technique is called a semi visible read (we don’t know which transactions are possibly going to encounter a conflict, but we do know if there is at least one possible conflict).
There are 2 important optimizations to this design:
-# Eager full conflict scan
-# Read biases refs
+
+- Eager full conflict scan
+- Read biases refs
**Eager full conflict scan**
****************************
-The reasons why short transactions always do a full conflict scan is that doing semi visible reads, relies doing more expensive synchronization operations (e.g. doing a cas to increase the surplus of readers, or doing a cas to decrease it).
+The reasons why short transactions always do a full conflict scan is that doing semi visible reads, relies on doing more expensive synchronization operations (e.g. doing a CAS to increase the surplus of readers, or doing a CAS to decrease it).
**Read biased vs update biased.**
*********************************
-The problem with semi visible reads is that certain structures (e.g. the root of a tree) can form a contention point (because of the arrives/departs) even though it mostly is read. To reduce contention, a ref can become read biased after a certain number of reads by transactions that use semi visible reads is done. Once it has become read biased, no arrives and departs are required any more, but once it the Ref is updated it will always increment the conflict counter because it doesn’t know if there are any conflicting readers.
+The problem with semi visible reads is that certain structures (e.g. the root of a tree) can form a contention point (because of the arrives/departs) even though it mostly is read. To reduce contention, a ref can become read biased after a certain number of reads by transactions that use semi visible reads is done. Once it has become read biased, no arrives and departs are required any more, but once the Ref is updated it will always increment the conflict counter because it doesn’t know if there are any conflicting readers.
-Visible reads, semi visible reads
-Read tracking
+TODO:
-strict isolation
-eager conflict detection
-deferred write, no dirty read possible
+- Visible reads, semi visible reads
+- Read tracking
-isolation level
-optimistic
-various levels of pessimistic behavior
+- strict isolation
+- eager conflict detection
+- deferred write, no dirty read possible
+
+- isolation level
+- optimistic
+- various levels of pessimistic behavior
diff --git a/akka-docs/pending/testkit.rst b/akka-docs/pending/testkit.rst
index d2d177948f..65aeac00b6 100644
--- a/akka-docs/pending/testkit.rst
+++ b/akka-docs/pending/testkit.rst
@@ -8,7 +8,7 @@ Overview
Testing actors comprises several aspects, which can have different weight according to the concrete project at hand:
* If you have a collection of actors which performs a certain function, you may want to apply defined stimuli and observe the delivery of the desired result messages to a test actor; in this case the ***TestKit*** trait will likely interest you.
-* If you encounter undesired behaviour (exceptions, dead-locks) and want to nail down the cause, it might help to run the actors in question using the ***CallingThreadDispatcher***; this dispatcher is strictly less powerful than the general purpose ones, but its deterministic behaviour and complete message stack can help debugging, unless your setup depends on concurrent execution for correctness.
+* If you encounter undesired behavior (exceptions, dead-locks) and want to nail down the cause, it might help to run the actors in question using the ***CallingThreadDispatcher***; this dispatcher is strictly less powerful than the general purpose ones, but its deterministic behavior and complete message stack can help debugging, unless your setup depends on concurrent execution for correctness.
* For real unit tests of one actor body at a time, there soon will be a special ***TestActorRef*** which allows access to the innards and enables running without a dispatcher.
TestKit
@@ -42,7 +42,7 @@ CallingThreadDispatcher
This special purpose dispatcher was conceived to enable collection of the full stack trace accumulated during processing of a complete message chain. The idea is to run invocations always on the calling thread, except when the target actor is already running on the current thread; in that case it is necessary to queue the invocation and run it after the current invocation on that actor has finished processing. This design implies that any invocation which blocks waiting on some future action to be done by the current thread will dead-lock. Hence, the CallingThreadDispatcher offers strictly more possibilities to dead-lock than a standard dispatcher.
-One nice property is that this feature can help verify that your design is dead-lock free: if you run only on this dispatcher and utilitze only one thread, then a successful run implies that for the given set of inputs there cannot be a dead-lock. (This is unfortunately not a hard guarantee, as long as your actor behavior depends on the dispatcher used, e.g. you could sabotage it by explicitly dead-locking only if self.dispatcher != CallingThreadDispatcher.)
+One nice property is that this feature can help verify that your design is dead-lock free: if you run only on this dispatcher and utilize only one thread, then a successful run implies that for the given set of inputs there cannot be a dead-lock. (This is unfortunately not a hard guarantee, as long as your actor behavior depends on the dispatcher used, e.g. you could sabotage it by explicitly dead-locking only if self.dispatcher != CallingThreadDispatcher.)
TestActorRef (coming soon ...)
------------------------------
diff --git a/akka-docs/pending/actor-registry-scala.rst b/akka-docs/scala/actor-registry.rst
similarity index 100%
rename from akka-docs/pending/actor-registry-scala.rst
rename to akka-docs/scala/actor-registry.rst
diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst
index 70f9e0cfcc..ed186e17ba 100644
--- a/akka-docs/scala/actors.rst
+++ b/akka-docs/scala/actors.rst
@@ -1,5 +1,9 @@
-Actors
-======
+Actors (Scala)
+==============
+
+.. sidebar:: Contents
+
+ .. contents:: :local:
Module stability: **SOLID**
@@ -7,7 +11,7 @@ The `Actor Model `_ provides a higher
The API of Akka’s Actors is similar to Scala Actors which has borrowed some of its syntax from Erlang.
-The Akka 0.9 release introduced a new concept; ActorRef, which requires some refactoring. If you are new to Akka just read along, but if you have used Akka 0.6.x, 0.7.x and 0.8.x then you might be helped by the :doc:`0.8.x => 0.9.x migration guide `
+The Akka 0.9 release introduced a new concept; ActorRef, which requires some refactoring. If you are new to Akka just read along, but if you have used Akka 0.6.x, 0.7.x and 0.8.x then you might be helped by the :doc:`0.8.x => 0.9.x migration guide `
Creating Actors
---------------
@@ -26,6 +30,9 @@ Here is an example:
.. code-block:: scala
+ import akka.actor.Actor
+ import akka.event.EventHandler
+
class MyActor extends Actor {
def receive = {
case "test" => EventHandler.info(this, "received test")
@@ -372,7 +379,7 @@ Actors are started by invoking the ``start`` method.
val actor = actorOf[MyActor]
actor.start()
-You can create and start the ``Actor`` in a oneliner like this:
+You can create and start the ``Actor`` in a one liner like this:
.. code-block:: scala
@@ -382,7 +389,7 @@ When you start the ``Actor`` then it will automatically call the ``def preStart`
.. code-block:: scala
- override def preStart = {
+ override def preStart() = {
... // initialization code
}
@@ -399,7 +406,7 @@ When stop is called then a call to the ``def postStop`` callback method will tak
.. code-block:: scala
- override def postStop = {
+ override def postStop() = {
... // clean up resources
}
diff --git a/akka-docs/pending/agents-scala.rst b/akka-docs/scala/agents.rst
similarity index 89%
rename from akka-docs/pending/agents-scala.rst
rename to akka-docs/scala/agents.rst
index 9adb9e9f81..dc62000995 100644
--- a/akka-docs/pending/agents-scala.rst
+++ b/akka-docs/scala/agents.rst
@@ -1,6 +1,10 @@
Agents (Scala)
==============
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
Agents in Akka were inspired by `agents in Clojure `_.
@@ -26,7 +30,7 @@ An Agent will be running until you invoke ``close`` on it. Then it will be eligi
.. code-block:: scala
- agent.close
+ agent.close()
Updating Agents
---------------
@@ -88,6 +92,29 @@ Transactional Agents
If an Agent is used within an enclosing transaction, then it will participate in that transaction. If you send to an Agent within a transaction then the dispatch to the Agent will be held until that transaction commits, and discarded if the transaction is aborted.
+.. code-block:: scala
+
+ import akka.agent.Agent
+ import akka.stm._
+
+ def transfer(from: Agent[Int], to: Agent[Int], amount: Int): Boolean = {
+ atomic {
+ if (from.get < amount) false
+ else {
+ from send (_ - amount)
+ to send (_ + amount)
+ true
+ }
+ }
+ }
+
+ val from = Agent(100)
+ val to = Agent(20)
+ val ok = transfer(from, to, 50)
+
+ from() // -> 50
+ to() // -> 70
+
Monadic usage
-------------
@@ -101,6 +128,7 @@ Example of a monadic usage:
val agent2 = Agent(5)
// uses foreach
+ var result = 0
for (value <- agent1) {
result = value + 1
}
@@ -115,7 +143,7 @@ Example of a monadic usage:
value2 <- agent2
} yield value1 + value2
- agent1.close
- agent2.close
- agent3.close
- agent4.close
+ agent1.close()
+ agent2.close()
+ agent3.close()
+ agent4.close()
diff --git a/akka-docs/pending/dispatchers-scala.rst b/akka-docs/scala/dispatchers.rst
similarity index 96%
rename from akka-docs/pending/dispatchers-scala.rst
rename to akka-docs/scala/dispatchers.rst
index 35df55724f..35285c20fa 100644
--- a/akka-docs/pending/dispatchers-scala.rst
+++ b/akka-docs/scala/dispatchers.rst
@@ -1,6 +1,10 @@
Dispatchers (Scala)
===================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
The Dispatcher is an important piece that allows you to configure the right semantics and parameters for optimal performance, throughput and scalability. Different Actors have different needs.
@@ -124,7 +128,7 @@ If you don't define a the 'throughput' option in the configuration file then the
Browse the `ScalaDoc `_ or look at the code for all the options available.
Priority event-based
-^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^
Sometimes it's useful to be able to specify priority order of messages, that is done by using PriorityExecutorBasedEventDrivenDispatcher and supply
a java.util.Comparator[MessageInvocation] or use a akka.dispatch.PriorityGenerator (recommended):
@@ -153,7 +157,7 @@ Creating a PriorityExecutorBasedEventDrivenDispatcher using PriorityGenerator:
a.dispatcher = new PriorityExecutorBasedEventDrivenDispatcher("foo", gen)
a.start // Start the Actor
- a.dispatcher.suspend(a) // Suspening the actor so it doesn't start to treat the messages before we have enqueued all of them :-)
+ a.dispatcher.suspend(a) // Suspending the actor so it doesn't start to treat the messages before we have enqueued all of them :-)
a ! 'lowpriority
a ! 'lowpriority
@@ -231,11 +235,13 @@ For the 'ExecutorBasedEventDrivenDispatcher' and the 'ExecutorBasedWorkStealingD
For the 'ThreadBasedDispatcher', it is non-shareable between actors, and associates a dedicated Thread with the actor.
Making it bounded (by specifying a capacity) is optional, but if you do, you need to provide a pushTimeout (default is 10 seconds). When trying to send a message to the Actor it will throw a MessageQueueAppendFailedException("BlockingMessageTransferQueue transfer timed out") if the message cannot be added to the mailbox within the time specified by the pushTimeout.
-``_
-class MyActor extends Actor {
- import akka.util.duration._
- self.dispatcher = Dispatchers.newThreadBasedDispatcher(self, mailboxCapacity = 100,
- pushTimeOut = 10 seconds)
- ...
-}
-``_
+.. code-block:: scala
+
+ class MyActor extends Actor {
+ import akka.util.duration._
+ self.dispatcher = Dispatchers.newThreadBasedDispatcher(self, mailboxCapacity = 100,
+ pushTimeOut = 10 seconds)
+ ...
+ }
+
+
diff --git a/akka-docs/scala/fsm.rst b/akka-docs/scala/fsm.rst
index a23fd9edf4..3b5fdd4394 100644
--- a/akka-docs/scala/fsm.rst
+++ b/akka-docs/scala/fsm.rst
@@ -1,5 +1,6 @@
+###
FSM
-===
+###
.. sidebar:: Contents
@@ -14,7 +15,7 @@ FSM
Module stability: **STABLE**
Overview
-++++++++
+========
The FSM (Finite State Machine) is available as a mixin for the akka Actor and
is best described in the `Erlang design principles
@@ -29,7 +30,7 @@ These relations are interpreted as meaning:
*If we are in state S and the event E occurs, we should perform the actions A and make a transition to the state S'.*
A Simple Example
-++++++++++++++++
+================
To demonstrate the usage of states we start with a simple FSM without state
data. The state can be of any type so for this example we create the states A,
@@ -42,7 +43,7 @@ B and C.
case object B extends ExampleState
case object C extends ExampleState
-Now lets create an object representing the FSM and defining the behaviour.
+Now lets create an object representing the FSM and defining the behavior.
.. code-block:: scala
@@ -94,7 +95,7 @@ FSM is finished by calling the :func:`initialize` method as last part of the
ABC constructor.
State Data
-++++++++++
+==========
The FSM can also hold state data associated with the internal state of the
state machine. The state data can be of any type but to demonstrate let's look
@@ -152,7 +153,7 @@ This encapsulation is what makes state machines a powerful abstraction, e.g.
for handling socket states in a network server application.
Reference
-+++++++++
+=========
This section describes the DSL in a more formal way, refer to `Examples`_ for more sample material.
@@ -194,24 +195,7 @@ The :class:`FSM` trait takes two type parameters:
Defining Timeouts
-----------------
-The :class:`FSM` module uses :class:`akka.util.Duration` for all timing
-configuration, which includes a mini-DSL:
-
-.. code-block:: scala
-
- import akka.util.duration._ // notice the small d
-
- val fivesec = 5.seconds
- val threemillis = 3.millis
- val diff = fivesec - threemillis
-
-.. note::
-
- You may leave out the dot if the expression is clearly delimited (e.g.
- within parentheses or in an argument list), but it is recommended to use it
- if the time unit is the last token on a line, otherwise semi-colon inference
- might go wrong, depending on what starts the next line.
-
+The :class:`FSM` module uses :ref:`Duration` for all timing configuration.
Several methods, like :func:`when()` and :func:`startWith()` take a
:class:`FSM.Timeout`, which is an alias for :class:`Option[Duration]`. There is
an implicit conversion available in the :obj:`FSM` object which makes this
@@ -344,7 +328,7 @@ state variable, as everything within the FSM actor is running single-threaded
anyway.
Internal Monitoring
-*******************
+^^^^^^^^^^^^^^^^^^^
Up to this point, the FSM DSL has been centered on states and events. The dual
view is to describe it as a series of transitions. This is enabled by the
@@ -398,7 +382,7 @@ are still executed in declaration order, though.
a certain state cannot be forgot when adding new target states.
External Monitoring
-*******************
+^^^^^^^^^^^^^^^^^^^
External actors may be registered to be notified of state transitions by
sending a message :class:`SubscribeTransitionCallBack(actorRef)`. The named
@@ -476,7 +460,7 @@ As for the :func:`whenUnhandled` case, this handler is not stacked, so each
invocation of :func:`onTermination` replaces the previously installed handler.
Examples
-++++++++
+========
A bigger FSM example can be found in the sources:
diff --git a/akka-docs/scala/index.rst b/akka-docs/scala/index.rst
index 645efccf41..d5269336aa 100644
--- a/akka-docs/scala/index.rst
+++ b/akka-docs/scala/index.rst
@@ -5,4 +5,14 @@ Scala API
:maxdepth: 2
actors
+ typed-actors
+ actor-registry
+ agents
+ stm
+ transactors
+ remote-actors
+ serialization
+ dispatchers
fsm
+ testing
+ tutorial-chat-server
diff --git a/akka-docs/scala/migration-guide-0.7.x-0.8.x.rst b/akka-docs/scala/migration-guide-0.7.x-0.8.x.rst
deleted file mode 100644
index 5c45eb76c1..0000000000
--- a/akka-docs/scala/migration-guide-0.7.x-0.8.x.rst
+++ /dev/null
@@ -1,94 +0,0 @@
-Migrate from 0.7.x to 0.8.x
-===========================
-
-This is a case-by-case migration guide from Akka 0.7.x (on Scala 2.7.7) to Akka 0.8.x (on Scala 2.8.x)
-------------------------------------------------------------------------------------------------------
-
-Cases:
-======
-
-Actor.send is removed and replaced in full with Actor.!
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code-block:: scala
-
- myActor send "test"
-
-becomes
-
-.. code-block:: scala
-
- myActor ! "test"
-
-Actor.! now has it's implicit sender defaulted to None
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code-block:: scala
-
- def !(message: Any)(implicit sender: Option[Actor] = None)
-
-"import Actor.Sender.Self" has been removed because it's not needed anymore
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Remove
-
-.. code-block:: scala
-
- import Actor.Sender.Self
-
-Actor.spawn now uses manifests instead of concrete class types
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code-block:: scala
-
- val someActor = spawn(classOf[MyActor])
-
-becomes
-
-.. code-block:: scala
-
- val someActor = spawn[MyActor]
-
-Actor.spawnRemote now uses manifests instead of concrete class types
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code-block:: scala
-
- val someActor = spawnRemote(classOf[MyActor],"somehost",1337)
-
-becomes
-
-.. code-block:: scala
-
- val someActor = spawnRemote[MyActor]("somehost",1337)
-
-Actor.spawnLink now uses manifests instead of concrete class types
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code-block:: scala
-
- val someActor = spawnLink(classOf[MyActor])
-
-becomes
-
-.. code-block:: scala
-
- val someActor = spawnLink[MyActor]
-
-Actor.spawnLinkRemote now uses manifests instead of concrete class types
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. code-block:: scala
-
- val someActor = spawnLinkRemote(classOf[MyActor],"somehost",1337)
-
-becomes
-
-.. code-block:: scala
-
- val someActor = spawnLinkRemote[MyActor]("somehost",1337)
-
-**Transaction.atomic and friends are moved into Transaction.Local._ and Transaction.Global._**
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-We now make a difference between transaction management that are local within a thread and global across many threads (and actors).
diff --git a/akka-docs/scala/migration-guide-0.8.x-0.9.x.rst b/akka-docs/scala/migration-guide-0.8.x-0.9.x.rst
deleted file mode 100644
index 359cb01602..0000000000
--- a/akka-docs/scala/migration-guide-0.8.x-0.9.x.rst
+++ /dev/null
@@ -1,170 +0,0 @@
-**This document describes between the 0.8.x and the 0.9 release.**
-
-Background for the new ActorRef
-===============================
-
-In the work towards 0.9 release we have now done a major change to how Actors are created. In short we have separated identity and value, created an 'ActorRef' that holds the actual Actor instance. This allows us to do many great things such as for example:
-
-* Create serializable, immutable, network-aware Actor references that can be freely shared across the network. They "remember" their origin and will always work as expected.
-* Not only kill and restart the same supervised Actor instance when it has crashed (as we do now), but dereference it, throw it away and make it eligible for garbage collection.
-* etc. much more
-
-These work very much like the 'PID' (process id) in Erlang.
-
-These changes means that there is no difference in defining Actors. You still use the old Actor trait, all methods are there etc. But you can't just new this Actor up and send messages to it since all its public API methods are gone. They now reside in a new class; 'ActorRef' and use need to use instances of this class to interact with the Actor (sending messages etc.).
-
-Here is a short migration guide with the things that you have to change. It is a big conceptual change but in practice you don't have to change much.
-
-Migration Guide
-===============
-
-Creating Actors with default constructor
-----------------------------------------
-
-From:
-
-.. code-block:: scala
-
- val a = new MyActor
- a ! msg
-
-To:
-
-.. code-block:: scala
-
- import Actor._
- val a = actorOf[MyActor]
- a ! msg
-
-You can also start it in the same statement:
-
-.. code-block:: scala
-
- val a = actorOf[MyActor].start
-
-Creating Actors with non-default constructor
---------------------------------------------
-
-From:
-
-.. code-block:: scala
-
- val a = new MyActor(..)
- a ! msg
-
-To:
-
-.. code-block:: scala
-
- import Actor._
- val a = actorOf(new MyActor(..))
- a ! msg
-
-Use of 'self' ActorRef API
---------------------------
-
-Where you have used 'this' to refer to the Actor from within itself now use 'self':
-
-.. code-block:: scala
-
- self ! MessageToMe
-
-Now the Actor trait only has the callbacks you can implement:
-* receive
-* postRestart/preRestart
-* init/shutdown
-
-It has no state at all.
-
-All API has been moved to ActorRef. The Actor is given its ActorRef through the 'self' member variable.
-Here you find functions like:
-* !, !!, !!! and forward
-* link, unlink, startLink, spawnLink etc
-* makeTransactional, makeRemote etc.
-* start, stop
-* etc.
-
-Here you also find fields like
-* dispatcher = ...
-* id = ...
-* lifeCycle = ...
-* faultHandler = ...
-* trapExit = ...
-* etc.
-
-This means that to use them you have to prefix them with 'self', like this:
-
-.. code-block:: scala
-
- self ! Message
-
-However, for convenience you can import these functions and fields like below, which will allow you do drop the 'self' prefix:
-
-.. code-block:: scala
-
- class MyActor extends Actor {
- import self._
- id = ...
- dispatcher = ...
- spawnLink[OtherActor]
- ...
- }
-
-Serialization
-=============
-
-If you want to serialize it yourself, here is how to do it:
-
-.. code-block:: scala
-
- val actorRef1 = actorOf[MyActor]
-
- val bytes = actorRef1.toBinary
-
- val actorRef2 = ActorRef.fromBinary(bytes)
-
-If you are also using Protobuf then you can use the methods that work with Protobuf's Messages directly.
-
-.. code-block:: scala
-
- val actorRef1 = actorOf[MyActor]
-
- val protobufMessage = actorRef1.toProtocol
-
- val actorRef2 = ActorRef.fromProtocol(protobufMessage)
-
-Camel
-======
-
-Some methods of the se.scalablesolutions.akka.camel.Message class have been deprecated in 0.9. These are
-
-.. code-block:: scala
-
- package se.scalablesolutions.akka.camel
-
- case class Message(...) {
- // ...
- @deprecated def bodyAs[T](clazz: Class[T]): T
- @deprecated def setBodyAs[T](clazz: Class[T]): Message
- // ...
- }
-
-They will be removed in 1.0. Instead use
-
-.. code-block:: scala
-
- package se.scalablesolutions.akka.camel
-
- case class Message(...) {
- // ...
- def bodyAs[T](implicit m: Manifest[T]): T =
- def setBodyAs[T](implicit m: Manifest[T]): Message
- // ...
- }
-
-Usage example:
-.. code-block:: scala
-
- val m = Message(1.4)
- val b = m.bodyAs[String]
-
diff --git a/akka-docs/scala/migration-guide-0.9.x-0.10.x.rst b/akka-docs/scala/migration-guide-0.9.x-0.10.x.rst
deleted file mode 100644
index 68ec0cb087..0000000000
--- a/akka-docs/scala/migration-guide-0.9.x-0.10.x.rst
+++ /dev/null
@@ -1,45 +0,0 @@
-Migration Guide from Akka 0.9.x to Akka 0.10.x
-==============================================
-
-Module akka-camel
------------------
-
-The following list summarizes the breaking changes since Akka 0.9.1.
-
-* CamelService moved from package se.scalablesolutions.akka.camel.service one level up to se.scalablesolutions.akka.camel.
-* CamelService.newInstance removed. For starting and stopping a CamelService, applications should use
-** CamelServiceManager.startCamelService and
-** CamelServiceManager.stopCamelService.
-* Existing def receive = produce method definitions from Producer implementations must be removed (resolves compile error: method receive needs override modifier).
-* The Producer.async method and the related Sync trait have been removed. This is now fully covered by Camel's `asynchronous routing engine `_.
-* @consume annotation can not placed any longer on actors (i.e. on type-level), only on typed actor methods. Consumer actors must mixin the Consumer trait.
-* @consume annotation moved to package se.scalablesolutions.akka.camel.
-
-Logging
--------
-
-We've switched to Logback (SLF4J compatible) for the logging, if you're having trouble seeing your log output you'll need to make sure that there's a logback.xml available on the classpath or you'll need to specify the location of the logback.xml file via the system property, ex: -Dlogback.configurationFile=/path/to/logback.xml
-
-Configuration
--------------
-
-* The configuration is now JSON-style (see below).
-* Now you can define the time-unit to be used throughout the config file:
-
-.. code-block:: ruby
-
- akka {
- version = "0.10"
- time-unit = "seconds" # default timeout time unit for all timeout properties throughout the config
-
- actor {
- timeout = 5 # default timeout for future based invocations
- throughput = 5 # default throughput for ExecutorBasedEventDrivenDispatcher
- }
- ...
- }
-
-RemoteClient events
--------------------
-
-All events now has a reference to the RemoteClient instance instead of 'hostname' and 'port'. This is more flexible. Enables simpler reconnecting etc.
diff --git a/akka-docs/scala/migration-guide-1.0.x-1.1.x.rst b/akka-docs/scala/migration-guide-1.0.x-1.1.x.rst
deleted file mode 100644
index c32b2545ac..0000000000
--- a/akka-docs/scala/migration-guide-1.0.x-1.1.x.rst
+++ /dev/null
@@ -1,37 +0,0 @@
-Akka has now moved to Scala 2.9.x
-^^^^^^^^^^^^^^^^^^^^
-
-Akka HTTP
-=========
-
-# akka.servlet.Initializer has been moved to ``akka-kernel`` to be able to have ``akka-http`` not depend on ``akka-remote``, if you don't want to use the class for kernel, just create your own version of ``akka.servlet.Initializer``, it's just a couple of lines of code and there is instructions here: `Akka Http Docs `_
-# akka.http.ListWriter has been removed in full, if you use it and want to keep using it, here's the code: `ListWriter `_
-# Jersey-server is now a "provided" dependency for ``akka-http``, so you'll need to add the dependency to your project, it's built against Jersey 1.3
-
-Akka Actor
-==========
-
-# is now dependency free, with the exception of the dependency on the ``scala-library.jar``
-# does not bundle any logging anymore, but you can subscribe to events within Akka by registering an event handler on akka.aevent.EventHandler or by specifying the ``FQN`` of an Actor in the akka.conf under akka.event-handlers; there is an ``akka-slf4j`` module which still provides the Logging trait and a default ``SLF4J`` logger adapter.
-Don't forget to add a SLF4J backend though, we recommend:
-
-.. code-block:: scala
- lazy val logback = "ch.qos.logback" % "logback-classic" % "0.9.28"
-
-# If you used HawtDispatcher and want to continue using it, you need to include akka-dispatcher-extras.jar from Akka Modules, in your akka.conf you need to specify: ``akka.dispatch.HawtDispatcherConfigurator`` instead of ``HawtDispatcher``
-# FSM: the onTransition method changed from Function1 to PartialFunction; there is an implicit conversion for the precise types in place, but it may be necessary to add an underscore if you are passing an eta-expansion (using a method as function value).
-
-Akka Typed Actor
-================
-
-All methods starting with 'get*' are deprecated and will be removed in post 1.1 release.
-
-Akka Remote
-===========
-
-# ``UnparsebleException`` has been renamed to ``CannotInstantiateRemoteExceptionDueToRemoteProtocolParsingErrorException(exception, classname, message)``
-
-Akka Testkit
-============
-
-The TestKit moved into the akka-testkit subproject and correspondingly into the ``akka.testkit` package.
diff --git a/akka-docs/scala/migration-guides.rst b/akka-docs/scala/migration-guides.rst
deleted file mode 100644
index 361f8e3c7a..0000000000
--- a/akka-docs/scala/migration-guides.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Here are migration guides for the latest releases
-=================================================
-
-* `Migrate 0.7.x -> 0.8.x `_
-* `Migrate 0.8.x -> 0.9.x `_
-* `Migrate 0.9.x -> 0.10.x `_
-* `Migrate 0.10.x -> 1.0.x `_
-* `Migrate 1.0.x -> 1.1.x `_
diff --git a/akka-docs/pending/remote-actors-scala.rst b/akka-docs/scala/remote-actors.rst
similarity index 81%
rename from akka-docs/pending/remote-actors-scala.rst
rename to akka-docs/scala/remote-actors.rst
index fef71e69e5..0f7e68d095 100644
--- a/akka-docs/pending/remote-actors-scala.rst
+++ b/akka-docs/scala/remote-actors.rst
@@ -1,13 +1,17 @@
Remote Actors (Scala)
=====================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
-Akka supports starting Actors and Typed Actors on remote nodes using a very efficient and scalable NIO implementation built upon `JBoss Netty `_ and `Google Protocol Buffers `_ .
+Akka supports starting and interacting with Actors and Typed Actors on remote nodes using a very efficient and scalable NIO implementation built upon `JBoss Netty `_ and `Google Protocol Buffers `_ .
-The usage is completely transparent both in regards to sending messages and error handling and propagation as well as supervision, linking and restarts. You can send references to other Actors as part of the message.
+The usage is completely transparent with local actors, both in regards to sending messages and error handling and propagation as well as supervision, linking and restarts. You can send references to other Actors as part of the message.
-You can find a runnable sample `here `_.
+You can find a runnable sample `here `__.
Starting up the remote service
------------------------------
@@ -15,7 +19,7 @@ Starting up the remote service
Starting remote service in user code as a library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Here is how to start up the RemoteNode and specify the hostname and port programatically:
+Here is how to start up the RemoteNode and specify the hostname and port programmatically:
.. code-block:: scala
@@ -64,7 +68,7 @@ If you invoke 'shutdown' on the server then the connection will be closed.
import akka.actor.Actor._
- remote.shutdown
+ remote.shutdown()
Connecting and shutting down a client explicitly
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -74,6 +78,7 @@ Normally you should not have to start and stop the client connection explicitly
.. code-block:: scala
import akka.actor.Actor._
+ import java.net.InetSocketAddress
remote.shutdownClientConnection(new InetSocketAddress("localhost", 6666)) //Returns true if successful, false otherwise
remote.restartClientConnection(new InetSocketAddress("localhost", 6666)) //Returns true if successful, false otherwise
@@ -143,12 +148,6 @@ The default behavior is that the remote client will maintain a transaction log o
If you choose a capacity higher than 0, then a bounded queue will be used and if the limit of the queue is reached then a 'RemoteClientMessageBufferException' will be thrown.
-You can also get an Array with all the messages that the remote client has failed to send. Since the remote client events passes you an instance of the RemoteClient you have an easy way to act upon failure and do something with these messages (while waiting for them to be retried).
-
-.. code-block:: scala
-
- val pending: Array[Any] = Actor.remote.pendingMessages
-
Running Remote Server in untrusted mode
---------------------------------------
@@ -255,24 +254,16 @@ You can also generate the secure cookie by using the 'Crypt' object and its 'gen
The secure cookie is a cryptographically secure randomly generated byte array turned into a SHA-1 hash.
-Remote Actors
--------------
-
-Akka has two types of remote actors:
-
-* Client-initiated and managed. Here it is the client that creates the remote actor and "moves it" to the server.
-* Server-initiated and managed. Here it is the server that creates the remote actor and the client can ask for a handle to this actor.
-
-They are good for different use-cases. The client-initiated are great when you want to monitor an actor on another node since it allows you to link to it and supervise it using the regular supervision semantics. They also make RPC completely transparent. The server-initiated, on the other hand, are great when you have a service running on the server that you want clients to connect to, and you want full control over the actor on the server side for security reasons etc.
-
Client-managed Remote Actors
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+----------------------------
DEPRECATED AS OF 1.1
-When you define an actors as being remote it is instantiated as on the remote host and your local actor becomes a proxy, it works as a handle to the remote actor. The real execution is always happening on the remote node.
+The client creates the remote actor and "moves it" to the server.
-Actors can be made remote by calling remote().actorOf[MyActor](host, port)
+When you define an actor as being remote it is instantiated as on the remote host and your local actor becomes a proxy, it works as a handle to the remote actor. The real execution is always happening on the remote node.
+
+Actors can be made remote by calling remote.actorOf[MyActor](host, port)
Here is an example:
@@ -280,29 +271,30 @@ Here is an example:
import akka.actor.Actor
- class MyActor extends RemoteActor() {
+ class MyActor extends Actor {
def receive = {
case "hello" => self.reply("world")
}
}
- val remote = Actor.remote().actorOf[MyActor]("192.68.23.769", 2552)
+ val remoteActor = Actor.remote.actorOf[MyActor]("192.68.23.769", 2552)
An Actor can also start remote child Actors through one of the 'spawn/link' methods. These will start, link and make the Actor remote atomically.
.. code-block:: scala
...
- spawnRemote[MyActor](hostname, port)
- spawnLinkRemote[MyActor](hostname, port)
+ self.spawnRemote[MyActor](hostname, port, timeout)
+ self.spawnLinkRemote[MyActor](hostname, port, timeout)
...
Server-managed Remote Actors
----------------------------
+Here it is the server that creates the remote actor and the client can ask for a handle to this actor.
+
Server side setup
^^^^^^^^^^^^^^^^^
-
The API for server managed remote actors is really simple. 2 methods only:
.. code-block:: scala
@@ -318,7 +310,7 @@ The API for server managed remote actors is really simple. 2 methods only:
Actors created like this are automatically started.
-You can also register an actor by its UUD rather than ID or handle. This is done by prefixing the handle with the "uuid:" protocol.
+You can also register an actor by its UUID rather than ID or handle. This is done by prefixing the handle with the "uuid:" protocol.
.. code-block:: scala
@@ -332,7 +324,7 @@ Session bound server side setup
Session bound server managed remote actors work by creating and starting a new actor for every client that connects. Actors are stopped automatically when the client disconnects. The client side is the same as regular server managed remote actors. Use the function registerPerSession instead of register.
Session bound actors are useful if you need to keep state per session, e.g. username.
-They are also useful if you need to perform some cleanup when a client disconnects by overriding the postStop method as described `here `_
+They are also useful if you need to perform some cleanup when a client disconnects by overriding the postStop method as described `here `__
.. code-block:: scala
@@ -358,10 +350,10 @@ There are many variations on the 'remote#actorFor' method. Here are some of them
.. code-block:: scala
- ... = actorFor(className, hostname, port)
- ... = actorFor(className, timeout, hostname, port)
- ... = actorFor(uuid, className, hostname, port)
- ... = actorFor(uuid, className, timeout, hostname, port)
+ ... = remote.actorFor(className, hostname, port)
+ ... = remote.actorFor(className, timeout, hostname, port)
+ ... = remote.actorFor(uuid, className, hostname, port)
+ ... = remote.actorFor(uuid, className, timeout, hostname, port)
... // etc
All of these also have variations where you can pass in an explicit 'ClassLoader' which can be used when deserializing messages sent from the remote actor.
@@ -371,11 +363,16 @@ Running sample
Here is a complete running sample (also available `here `_):
+Paste in the code below into two sbt concole shells. Then run:
+
+- ServerInitiatedRemoteActorServer.run() in one shell
+- ServerInitiatedRemoteActorClient.run() in the other shell
+
.. code-block:: scala
import akka.actor.Actor
- import akka.util.Logging
import Actor._
+ import akka.event.EventHandler
class HelloWorldActor extends Actor {
def receive = {
@@ -385,27 +382,27 @@ Here is a complete running sample (also available `here self.reply("world")
}
@@ -430,11 +427,9 @@ Here is an example of overriding the 'id' field:
val actor = remote.actorOf[MyActor]("192.68.23.769", 2552)
-Remote Typed Actors
--------------------
-Client-managed Remote Actors
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Client-managed Remote Typed Actors
+----------------------------------
DEPRECATED AS OF 1.1
@@ -458,13 +453,13 @@ You can also define an Typed Actor to be remote programmatically when creating i
... // use pojo as usual
-Server-managed Remote Actors
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Server-managed Remote Typed Actors
+----------------------------------
WARNING: Remote TypedActors do not work with overloaded methods on your TypedActor, refrain from using overloading.
Server side setup
-*****************
+^^^^^^^^^^^^^^^^^
The API for server managed remote typed actors is nearly the same as for untyped actor
@@ -507,20 +502,20 @@ They are also useful if you need to perform some cleanup when a client disconnec
Note that the second argument in registerTypedPerSessionActor is an implicit function. It will be called to create an actor every time a session is established.
Client side usage
-*****************
+^^^^^^^^^^^^^^^^^
.. code-block:: scala
val actor = remote.typedActorFor(classOf[RegistrationService], "user-service", 5000L, "localhost", 2552)
actor.registerUser(…)
-There are variations on the 'RemoteClient#typedActorFor' method. Here are some of them:
+There are variations on the 'remote#typedActorFor' method. Here are some of them:
.. code-block:: scala
- ... = typedActorFor(interfaceClazz, serviceIdOrClassName, hostname, port)
- ... = typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port)
- ... = typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port, classLoader)
+ ... = remote.typedActorFor(interfaceClazz, serviceIdOrClassName, hostname, port)
+ ... = remote.typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port)
+ ... = remote.typedActorFor(interfaceClazz, serviceIdOrClassName, timeout, hostname, port, classLoader)
Data Compression Configuration
------------------------------
@@ -583,15 +578,19 @@ So a simple listener actor can look like this:
.. code-block:: scala
+ import akka.actor.Actor
+ import akka.actor.Actor._
+ import akka.remoteinterface._
+
val listener = actorOf(new Actor {
def receive = {
- case RemoteClientError(cause, client, address) => ... // act upon error
- case RemoteClientDisconnected(client, address) => ... // act upon disconnection
- case RemoteClientConnected(client, address) => ... // act upon connection
- case RemoteClientStarted(client, address) => ... // act upon client shutdown
- case RemoteClientShutdown(client, address) => ... // act upon client shutdown
- case RemoteClientWriteFailed(request, cause, client, address) => ... // act upon write failure
- case _ => //ignore other
+ case RemoteClientError(cause, client, address) => //... act upon error
+ case RemoteClientDisconnected(client, address) => //... act upon disconnection
+ case RemoteClientConnected(client, address) => //... act upon connection
+ case RemoteClientStarted(client, address) => //... act upon client shutdown
+ case RemoteClientShutdown(client, address) => //... act upon client shutdown
+ case RemoteClientWriteFailed(request, cause, client, address) => //... act upon write failure
+ case _ => // ignore other
}
}).start()
@@ -637,15 +636,19 @@ So a simple listener actor can look like this:
.. code-block:: scala
+ import akka.actor.Actor
+ import akka.actor.Actor._
+ import akka.remoteinterface._
+
val listener = actorOf(new Actor {
def receive = {
- case RemoteServerStarted(server) => ... // act upon server start
- case RemoteServerShutdown(server) => ... // act upon server shutdown
- case RemoteServerError(cause, server) => ... // act upon server error
- case RemoteServerClientConnected(server, clientAddress) => ... // act upon client connection
- case RemoteServerClientDisconnected(server, clientAddress) => ... // act upon client disconnection
- case RemoteServerClientClosed(server, clientAddress) => ... // act upon client connection close
- case RemoteServerWriteFailed(request, casue, server, clientAddress) => ... // act upon server write failure
+ case RemoteServerStarted(server) => //... act upon server start
+ case RemoteServerShutdown(server) => //... act upon server shutdown
+ case RemoteServerError(cause, server) => //... act upon server error
+ case RemoteServerClientConnected(server, clientAddress) => //... act upon client connection
+ case RemoteServerClientDisconnected(server, clientAddress) => //... act upon client disconnection
+ case RemoteServerClientClosed(server, clientAddress) => //... act upon client connection close
+ case RemoteServerWriteFailed(request, cause, server, clientAddress) => //... act upon server write failure
}
}).start()
@@ -662,7 +665,7 @@ Message Serialization
All messages that are sent to remote actors needs to be serialized to binary format to be able to travel over the wire to the remote node. This is done by letting your messages extend one of the traits in the 'akka.serialization.Serializable' object. If the messages don't implement any specific serialization trait then the runtime will try to use standard Java serialization.
-Here are some examples, but full documentation can be found in the `Serialization section `_.
+Here are some examples, but full documentation can be found in the :ref:`serialization-scala`.
Scala JSON
^^^^^^^^^^
@@ -676,7 +679,7 @@ Protobuf
Protobuf message specification needs to be compiled with 'protoc' compiler.
-.. code-block:: scala
+::
message ProtobufPOJO {
required uint64 id = 1;
@@ -697,26 +700,27 @@ Using the generated message builder to send the message to a remote actor:
SBinary
^^^^^^^
-``_
-case class User(firstNameLastName: Tuple2[String, String], email: String, age: Int) extends Serializable.SBinary[User] {
- import sbinary.DefaultProtocol._
+.. code-block:: scala
- def this() = this(null, null, 0)
+ case class User(firstNameLastName: Tuple2[String, String], email: String, age: Int) extends Serializable.SBinary[User] {
+ import sbinary.DefaultProtocol._
- implicit object UserFormat extends Format[User] {
- def reads(in : Input) = User(
- read[Tuple2[String, String]](in),
- read[String](in),
- read[Int](in))
- def writes(out: Output, value: User) = {
- write[Tuple2[String, String]](out, value. firstNameLastName)
- write[String](out, value.email)
- write[Int](out, value.age)
+ def this() = this(null, null, 0)
+
+ implicit object UserFormat extends Format[User] {
+ def reads(in : Input) = User(
+ read[Tuple2[String, String]](in),
+ read[String](in),
+ read[Int](in))
+ def writes(out: Output, value: User) = {
+ write[Tuple2[String, String]](out, value. firstNameLastName)
+ write[String](out, value.email)
+ write[Int](out, value.age)
+ }
}
+
+ def fromBytes(bytes: Array[Byte]) = fromByteArray[User](bytes)
+
+ def toBytes: Array[Byte] = toByteArray(this)
}
- def fromBytes(bytes: Array[Byte]) = fromByteArray[User](bytes)
-
- def toBytes: Array[Byte] = toByteArray(this)
-}
-``_
diff --git a/akka-docs/pending/serialization-scala.rst b/akka-docs/scala/serialization.rst
similarity index 85%
rename from akka-docs/pending/serialization-scala.rst
rename to akka-docs/scala/serialization.rst
index 93b738a176..39f9304bc8 100644
--- a/akka-docs/pending/serialization-scala.rst
+++ b/akka-docs/scala/serialization.rst
@@ -1,10 +1,16 @@
+.. _serialization-scala:
+
Serialization (Scala)
=====================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
Serialization of ActorRef
-=========================
+-------------------------
An Actor can be serialized in two different ways:
@@ -13,7 +19,7 @@ An Actor can be serialized in two different ways:
Both of these can be sent as messages over the network and/or store them to disk, in a persistent storage backend etc.
-Actor serialization in Akka is implemented through a type class 'Format[T <: Actor]' which publishes the 'fromBinary' and 'toBinary' methods for serialization. Here's the complete definition of the type class:
+Actor serialization in Akka is implemented through a type class ``Format[T <: Actor]`` which publishes the ``fromBinary`` and ``toBinary`` methods for serialization. Here's the complete definition of the type class:
.. code-block:: scala
@@ -31,15 +37,14 @@ Actor serialization in Akka is implemented through a type class 'Format[T <: Act
// client needs to implement Format[] for the respective actor
trait Format[T <: Actor] extends FromBinary[T] with ToBinary[T]
-**Deep serialization of an Actor and ActorRef**
------------------------------------------------
+Deep serialization of an Actor and ActorRef
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-You can serialize the whole actor deeply, e.g. both the 'ActorRef' and then instance of its 'Actor'. This can be useful if you want to move an actor from one node to another, or if you want to store away an actor, with its state, into a database.
+You can serialize the whole actor deeply, e.g. both the ``ActorRef`` and then instance of its ``Actor``. This can be useful if you want to move an actor from one node to another, or if you want to store away an actor, with its state, into a database.
Here is an example of how to serialize an Actor.
Step 1: Define the actor
-^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: scala
@@ -54,7 +59,6 @@ Step 1: Define the actor
}
Step 2: Implement the type class for the actor
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: scala
@@ -72,7 +76,6 @@ Step 2: Implement the type class for the actor
}
Step 3: Import the type class module definition and serialize / de-serialize
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: scala
@@ -90,7 +93,8 @@ Step 3: Import the type class module definition and serialize / de-serialize
(actor2 !! "hello").getOrElse("_") should equal("world 3")
}
-**Helper Type Class for Stateless Actors**
+Helper Type Class for Stateless Actors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If your actor is stateless, then you can use the helper trait that Akka provides to serialize / de-serialize. Here's the definition:
@@ -138,9 +142,10 @@ and use it for serialization:
(actor2 !! "hello").getOrElse("_") should equal("world")
}
-**Helper Type Class for actors with external serializer**
+Helper Type Class for actors with external serializer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Use the trait 'SerializerBasedActorFormat' for specifying serializers.
+Use the trait ``SerializerBasedActorFormat`` for specifying serializers.
.. code-block:: scala
@@ -192,14 +197,14 @@ and serialize / de-serialize ..
(actor2 !! "hello").getOrElse("_") should equal("world 3")
}
-**Serialization of a RemoteActorRef**
--------------------------------------
+Serialization of a RemoteActorRef
+---------------------------------
-You can serialize an 'ActorRef' to an immutable, network-aware Actor reference that can be freely shared across the network, a reference that "remembers" and stay mapped to its original Actor instance and host node, and will always work as expected.
+You can serialize an ``ActorRef`` to an immutable, network-aware Actor reference that can be freely shared across the network, a reference that "remembers" and stay mapped to its original Actor instance and host node, and will always work as expected.
-The 'RemoteActorRef' serialization is based upon Protobuf (Google Protocol Buffers) and you don't need to do anything to use it, it works on any 'ActorRef' (as long as the actor has **not** implemented one of the 'SerializableActor' traits, since then deep serialization will happen).
+The ``RemoteActorRef`` serialization is based upon Protobuf (Google Protocol Buffers) and you don't need to do anything to use it, it works on any ``ActorRef`` (as long as the actor has **not** implemented one of the ``SerializableActor`` traits, since then deep serialization will happen).
-Currently Akka will **not** autodetect an 'ActorRef' as part of your message and serialize it for you automatically, so you have to do that manually or as part of your custom serialization mechanisms.
+Currently Akka will **not** autodetect an ``ActorRef`` as part of your message and serialize it for you automatically, so you have to do that manually or as part of your custom serialization mechanisms.
Here is an example of how to serialize an Actor.
@@ -209,14 +214,14 @@ Here is an example of how to serialize an Actor.
val bytes = toBinary(actor1)
-To deserialize the 'ActorRef' to a 'RemoteActorRef' you need to use the 'fromBinaryToRemoteActorRef(bytes: Array[Byte])' method on the 'ActorRef' companion object:
+To deserialize the ``ActorRef`` to a ``RemoteActorRef`` you need to use the ``fromBinaryToRemoteActorRef(bytes: Array[Byte])`` method on the ``ActorRef`` companion object:
.. code-block:: scala
import RemoteActorSerialization._
val actor2 = fromBinaryToRemoteActorRef(bytes)
-You can also pass in a class loader to load the 'ActorRef' class and dependencies from:
+You can also pass in a class loader to load the ``ActorRef`` class and dependencies from:
.. code-block:: scala
@@ -226,14 +231,12 @@ You can also pass in a class loader to load the 'ActorRef' class and dependencie
Deep serialization of a TypedActor
----------------------------------
-Serialization of typed actors works almost the same way as untyped actors. You can serialize the whole actor deeply, e.g. both the 'proxied ActorRef' and the instance of its 'TypedActor'.
+Serialization of typed actors works almost the same way as untyped actors. You can serialize the whole actor deeply, e.g. both the 'proxied ActorRef' and the instance of its ``TypedActor``.
Here is the example from above implemented as a TypedActor.
-^
Step 1: Define the actor
-^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: scala
@@ -252,7 +255,6 @@ Step 1: Define the actor
}
Step 2: Implement the type class for the actor
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: scala
@@ -266,7 +268,6 @@ Step 2: Implement the type class for the actor
}
Step 3: Import the type class module definition and serialize / de-serialize
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: scala
@@ -278,12 +279,12 @@ Step 3: Import the type class module definition and serialize / de-serialize
val typedActor2: MyTypedActor = fromBinaryJ(bytes, f) //type hint needed
typedActor2.requestReply("hello")
--
+
Serialization of a remote typed ActorRef
----------------------------------------
-To deserialize the TypedActor to a 'RemoteTypedActorRef' (an aspectwerkz proxy to a RemoteActorRef) you need to use the 'fromBinaryToRemoteTypedActorRef(bytes: Array[Byte])' method on 'RemoteTypedActorSerialization' object:
+To deserialize the TypedActor to a ``RemoteTypedActorRef`` (an aspectwerkz proxy to a RemoteActorRef) you need to use the ``fromBinaryToRemoteTypedActorRef(bytes: Array[Byte])`` method on ``RemoteTypedActorSerialization`` object:
.. code-block:: scala
@@ -294,7 +295,7 @@ To deserialize the TypedActor to a 'RemoteTypedActorRef' (an aspectwerkz proxy t
val typedActor2 = fromBinaryToRemoteTypedActorRef(bytes, classLoader)
Compression
-===========
+-----------
Akka has a helper class for doing compression of binary data. This can be useful for example when storing data in one of the backing storages. It currently supports LZF which is a very fast compression algorithm suited for runtime dynamic compression.
@@ -309,24 +310,28 @@ Here is an example of how it can be used:
val uncompressBytes = Compression.LZF.uncompress(compressBytes)
Using the Serializable trait and Serializer class for custom serialization
-==========================================================================
+--------------------------------------------------------------------------
-If you are sending messages to a remote Actor and these messages implement one of the predefined interfaces/traits in the 'akka.serialization.Serializable.*' object, then Akka will transparently detect which serialization format it should use as wire protocol and will automatically serialize and deserialize the message according to this protocol.
+If you are sending messages to a remote Actor and these messages implement one of the predefined interfaces/traits in the ``akka.serialization.Serializable.*`` object, then Akka will transparently detect which serialization format it should use as wire protocol and will automatically serialize and deserialize the message according to this protocol.
Each serialization interface/trait in
-* akka.serialization.Serializable.*
-> has a matching serializer in
-* akka.serialization.Serializer.*
+
+- akka.serialization.Serializable.*
+
+has a matching serializer in
+
+- akka.serialization.Serializer.*
Note however that if you are using one of the Serializable interfaces then you don’t have to do anything else in regard to sending remote messages.
The ones currently supported are (besides the default which is regular Java serialization):
-* ScalaJON (Scala only)
-* JavaJSON (Java but some Scala structures)
-* SBinary (Scala only)
-* Protobuf (Scala and Java)
-Apart from the above, Akka also supports Scala object serialization through `SJSON `_ that implements APIs similar to 'akka.serialization.Serializer.*'. See the section on SJSON below for details.
+- ScalaJSON (Scala only)
+- JavaJSON (Java but some Scala structures)
+- SBinary (Scala only)
+- Protobuf (Scala and Java)
+
+Apart from the above, Akka also supports Scala object serialization through `SJSON `_ that implements APIs similar to ``akka.serialization.Serializer.*``. See the section on SJSON below for details.
Protobuf
--------
@@ -439,7 +444,7 @@ Here are the steps that you need to follow:
Serializer API using reflection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-You can also use the Serializer abstraction to serialize using reflection based serialization API of sjson. But we recommend using the type class based one, because reflection based serialization has limitations due to type erasure. Here's an example of reflection based serialization:
+You can also use the Serializer abstraction to serialize using the reflection based serialization API of sjson. But we recommend using the type class based one, because reflection based serialization has limitations due to type erasure. Here's an example of reflection based serialization:
.. code-block:: scala
@@ -481,8 +486,8 @@ You may also see this exception when trying to serialize a case class with out a
@BeanInfo case class Empty() // cannot be serialized
- SJSON: Scala
--------------
+SJSON: Scala
+------------
SJSON supports serialization of Scala objects into JSON. It implements support for built in Scala structures like List, Map or String as well as custom objects. SJSON is available as an Apache 2 licensed project on Github `here `_.
@@ -535,7 +540,7 @@ What you get back from is a JsValue, an abstraction of the JSON object model. Fo
Serialization of Embedded Objects
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- SJSON supports serialization of Scala objects that have other embedded objects. Suppose you have the following Scala classes .. Here Contact has an embedded Address Map ..
+SJSON supports serialization of Scala objects that have other embedded objects. Suppose you have the following Scala classes .. Here Contact has an embedded Address Map ..
.. code-block:: scala
@@ -593,7 +598,7 @@ With SJSON, I can do the following:
"Market Street" should equal(
(r ># { ('addresses ? obj) andThen ('residence ? obj) andThen ('street ? str) }))
-^
+
Changing property names during serialization
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -619,7 +624,7 @@ When this will be serialized out, the property name will be changed.
JsString("ISBN") -> JsString("012-456372")
)
-^
+
Serialization with ignore properties
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -653,7 +658,7 @@ The annotation @JSONProperty can be used to selectively ignore fields. When I se
Similarly, we can ignore properties of an object **only** if they are null and not ignore otherwise. Just specify the annotation @JSONProperty as @JSONProperty {val ignoreIfNull = true}.
-^
+
Serialization with Type Hints for Generic Data Members
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -672,7 +677,7 @@ Consider the following Scala class:
}
Because of erasure, you need to add the type hint declaratively through the annotation @JSONTypeHint that
-SJSON will pick up during serialization. No we can say:
+SJSON will pick up during serialization. Now we can say:
.. code-block:: scala
@@ -683,7 +688,7 @@ SJSON will pick up during serialization. No we can say:
c should equal(serializer.in[Contact](co))
}
-With optional generic data members, we need to provide the hint to SJSON through another annotation@OptionTypeHint.
+With optional generic data members, we need to provide the hint to SJSON through another annotation @OptionTypeHint.
.. code-block:: scala
@@ -714,7 +719,7 @@ Serialization works ok with optional members annotated as above.
}
}
-You can also specify a custom ClassLoader while using SJSON serializer:
+You can also specify a custom ClassLoader while using the SJSON serializer:
.. code-block:: scala
@@ -892,7 +897,8 @@ and the serialization in action in the REPL:
There are other nifty ways to implement case class serialization using sjson. For more details, have a look at the `wiki `_ for sjson.
-**JSON: Java**
+JSON: Java
+----------
Use the akka.serialization.Serialization.JavaJSON base class with its toJSONmethod. Akka’s Java JSON is based upon the Jackson library.
@@ -915,7 +921,7 @@ For your POJOs to be able to serialize themselves you have to extend the JavaJSO
SerializerFactory factory = new SerializerFactory();
MyMessage messageCopy = factory.getJavaJSON().in(json);
-Use the akka.serialization.SerializerFactory.getJavaJSON to do generic JSONserialization, e.g. serialize object that does not extend JavaJSON using the JSON serializer.
+Use the akka.serialization.SerializerFactory.getJavaJSON to do generic JSON serialization, e.g. serialize object that does not extend JavaJSON using the JSON serializer.
.. code-block:: java
@@ -924,7 +930,6 @@ Use the akka.serialization.SerializerFactory.getJavaJSON to do generic JSONseria
String json = factory.getJavaJSON().out(foo);
Foo fooCopy = factory.getJavaJSON().in(json, Foo.class);
--
SBinary: Scala
--------------
@@ -942,37 +947,43 @@ Here is an example of using the akka.serialization.Serializer.SBinary serializer
val usersCopy = Serializer.SBinary.in(bytes, Some(classOf[List[Tuple2[String,String]]]))
If you need to serialize your own user-defined objects then you have to do three things:
-# Define an empty constructor
-# Mix in the Serializable.SBinary[T] trait, and implement its methods:
-## fromBytes(bytes: Array[Byte])[T]
-## toBytes: Array[Byte]
-# Create an implicit sbinary.Format[T] object for your class. Which means that you have to define its two methods:
-## reads(in: Input): T; in which you read in all the fields in your object, using read[FieldType](in)and recreate it.
-## writes(out: Output, value: T): Unit; in which you write out all the fields in your object, usingwrite[FieldType](out, value.field).
+
+- Define an empty constructor
+- Mix in the Serializable.SBinary[T] trait, and implement its methods:
+
+ - fromBytes(bytes: Array[Byte])[T]
+ - toBytes: Array[Byte]
+
+- Create an implicit sbinary.Format[T] object for your class. Which means that you have to define its two methods:
+
+ - reads(in: Input): T; in which you read in all the fields in your object, using read[FieldType](in)and recreate it.
+ - writes(out: Output, value: T): Unit; in which you write out all the fields in your object, using write[FieldType](out, value.field).
Here is an example:
-``_
-case class User(val usernamePassword: Tuple2[String, String], val email: String, val age: Int)
- extends Serializable.SBinary[User] {
- import sbinary.DefaultProtocol._
- import sbinary.Operations._
- def this() = this(null, null, 0)
+.. code-block:: scala
- implicit object UserFormat extends Format[User] {
- def reads(in : Input) = User(
- read[Tuple2[String, String]](in),
- read[String](in),
- read[Int](in))
- def writes(out: Output, value: User) = {
- write[Tuple2[String, String]](out, value.usernamePassword)
- write[String](out, value.email)
- write[Int](out, value.age)
+ case class User(val usernamePassword: Tuple2[String, String], val email: String, val age: Int)
+ extends Serializable.SBinary[User] {
+ import sbinary.DefaultProtocol._
+ import sbinary.Operations._
+
+ def this() = this(null, null, 0)
+
+ implicit object UserFormat extends Format[User] {
+ def reads(in : Input) = User(
+ read[Tuple2[String, String]](in),
+ read[String](in),
+ read[Int](in))
+ def writes(out: Output, value: User) = {
+ write[Tuple2[String, String]](out, value.usernamePassword)
+ write[String](out, value.email)
+ write[Int](out, value.age)
+ }
}
+
+ def fromBytes(bytes: Array[Byte]) = fromByteArray[User](bytes)
+
+ def toBytes: Array[Byte] = toByteArray(this)
}
- def fromBytes(bytes: Array[Byte]) = fromByteArray[User](bytes)
-
- def toBytes: Array[Byte] = toByteArray(this)
-}
-``_
diff --git a/akka-docs/pending/stm-scala.rst b/akka-docs/scala/stm.rst
similarity index 75%
rename from akka-docs/pending/stm-scala.rst
rename to akka-docs/scala/stm.rst
index 0e1249fc48..42cd67ce2c 100644
--- a/akka-docs/pending/stm-scala.rst
+++ b/akka-docs/scala/stm.rst
@@ -1,10 +1,14 @@
Software Transactional Memory (Scala)
=====================================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
Overview of STM
-===============
+---------------
An `STM `_ turns the Java heap into a transactional data set with begin/commit/rollback semantics. Very much like a regular database. It implements the first three letters in ACID; ACI:
* Atomic
@@ -12,18 +16,19 @@ An `STM `_ turns the
* Isolated
Generally, the STM is not needed very often when working with Akka. Some use-cases (that we can think of) are:
-# When you really need composable message flows across many actors updating their **internal local** state but need them to do that atomically in one big transaction. Might not often, but when you do need this then you are screwed without it.
-# When you want to share a datastructure across actors.
-# When you need to use the persistence modules.
+
+- When you really need composable message flows across many actors updating their **internal local** state but need them to do that atomically in one big transaction. Might not be often, but when you do need this then you are screwed without it.
+- When you want to share a datastructure across actors.
+- When you need to use the persistence modules.
Akka’s STM implements the concept in `Clojure’s `_ STM view on state in general. Please take the time to read `this excellent document `_ and view `this presentation `_ by Rich Hickey (the genius behind Clojure), since it forms the basis of Akka’s view on STM and state in general.
The STM is based on Transactional References (referred to as Refs). Refs are memory cells, holding an (arbitrary) immutable value, that implement CAS (Compare-And-Swap) semantics and are managed and enforced by the STM for coordinated changes across many Refs. They are implemented using the excellent `Multiverse STM `_.
-Working with immutable collections can sometimes give bad performance due to extensive copying. Scala provides so-called persistent datastructures which makes working with immutable collections fast. They are immutable but with constant time access and modification. The use of structural sharing and an insert or update does not ruin the old structure, hence “persistent”. Makes working with immutable composite types fast. The persistent datastructures currently consist of a Map and Vector.
+Working with immutable collections can sometimes give bad performance due to extensive copying. Scala provides so-called persistent datastructures which makes working with immutable collections fast. They are immutable but with constant time access and modification. They use structural sharing and an insert or update does not ruin the old structure, hence “persistent”. Makes working with immutable composite types fast. The persistent datastructures currently consist of a Map and Vector.
Simple example
-==============
+--------------
Here is a simple example of an incremental counter using STM. This shows creating a ``Ref``, a transactional reference, and then modifying it within a transaction, which is delimited by ``atomic``.
@@ -43,15 +48,14 @@ Here is a simple example of an incremental counter using STM. This shows creatin
counter
// -> 2
-----
Ref
-===
+---
Refs (transactional references) are mutable references to values and through the STM allow the safe sharing of mutable data. Refs separate identity from value. To ensure safety the value stored in a Ref should be immutable (they can of course contain refs themselves). The value referenced by a Ref can only be accessed or swapped within a transaction. If a transaction is not available, the call will be executed in its own transaction (the call will be atomic). This is a different approach than the Clojure Refs, where a missing transaction results in an error.
Creating a Ref
---------------
+^^^^^^^^^^^^^^
You can create a Ref with or without an initial value.
@@ -66,7 +70,7 @@ You can create a Ref with or without an initial value.
val ref = Ref[Int]
Accessing the value of a Ref
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use ``get`` to access the value of a Ref. Note that if no initial value has been given then the value is initially ``null``.
@@ -96,7 +100,7 @@ If there is a chance that the value of a Ref is null then you can use ``opt``, w
}
Changing the value of a Ref
----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
To set a new value for a Ref you can use ``set`` (or equivalently ``swap``), which sets the new value and returns the old value.
@@ -137,7 +141,7 @@ You can also use ``alter`` which accepts a function that takes the old value and
// -> 6
Refs in for-comprehensions
---------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^
Ref is monadic and can be used in for-comprehensions.
@@ -173,10 +177,9 @@ Ref is monadic and can be used in for-comprehensions.
}
// -> Ref[Int]
-----
Transactions
-============
+------------
A transaction is delimited using ``atomic``.
@@ -186,13 +189,27 @@ A transaction is delimited using ``atomic``.
// ...
}
-Coordinated transactions and Transactors
-----------------------------------------
+All changes made to transactional objects are isolated from other changes, all make it or non make it (so failure atomicity) and are consistent. With the AkkaSTM you automatically have the Oracle version of the SERIALIZED isolation level, lower isolation is not possible. To make it fully serialized, set the writeskew property that checks if a writeskew problem is allowed to happen.
-If you need coordinated transactions across actors or threads then see `Transactors `_.
+Retries
+^^^^^^^
+
+A transaction is automatically retried when it runs into some read or write conflict, until the operation completes, an exception (throwable) is thrown or when there are too many retries. When a read or writeconflict is encountered, the transaction uses a bounded exponential backoff to prevent cause more contention and give other transactions some room to complete.
+
+If you are using non transactional resources in an atomic block, there could be problems because a transaction can be retried. If you are using print statements or logging, it could be that they are called more than once. So you need to be prepared to deal with this. One of the possible solutions is to work with a deferred or compensating task that is executed after the transaction aborts or commits.
+
+Unexpected retries
+^^^^^^^^^^^^^^^^^^
+
+It can happen for the first few executions that you get a few failures of execution that lead to unexpected retries, even though there is not any read or writeconflict. The cause of this is that speculative transaction configuration/selection is used. There are transactions optimized for a single transactional object, for 1..n and for n to unlimited. So based on the execution of the transaction, the system learns; it begins with a cheap one and upgrades to more expensive ones. Once it has learned, it will reuse this knowledge. It can be activated/deactivated using the speculative property on the TransactionFactory. In most cases it is best use the default value (enabled) so you get more out of performance.
+
+Coordinated transactions and Transactors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you need coordinated transactions across actors or threads then see :ref:`transactors-scala`.
Configuring transactions
-------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^
It's possible to configure transactions. The ``atomic`` method can take an implicit or explicit ``TransactionFactory``, which can determine properties of the transaction. A default transaction factory is used if none is specified explicitly or there is no implicit ``TransactionFactory`` in scope.
@@ -221,33 +238,36 @@ Configuring transactions with an **explicit** ``TransactionFactory``:
}
The following settings are possible on a TransactionFactory:
-* familyName - Family name for transactions. Useful for debugging.
-* readonly - Sets transaction as readonly. Readonly transactions are cheaper.
-* maxRetries - The maximum number of times a transaction will retry.
-* timeout - The maximum time a transaction will block for.
-* trackReads - Whether all reads should be tracked. Needed for blocking operations.
-* writeSkew - Whether writeskew is allowed. Disable with care.
-* blockingAllowed - Whether explicit retries are allowed.
-* interruptible - Whether a blocking transaction can be interrupted.
-* speculative - Whether speculative configuration should be enabled.
-* quickRelease - Whether locks should be released as quickly as possible (before whole commit).
-* propagation - For controlling how nested transactions behave.
-* traceLevel - Transaction trace level.
+
+- familyName - Family name for transactions. Useful for debugging.
+- readonly - Sets transaction as readonly. Readonly transactions are cheaper.
+- maxRetries - The maximum number of times a transaction will retry.
+- timeout - The maximum time a transaction will block for.
+- trackReads - Whether all reads should be tracked. Needed for blocking operations.
+- writeSkew - Whether writeskew is allowed. Disable with care.
+- blockingAllowed - Whether explicit retries are allowed.
+- interruptible - Whether a blocking transaction can be interrupted.
+- speculative - Whether speculative configuration should be enabled.
+- quickRelease - Whether locks should be released as quickly as possible (before whole commit).
+- propagation - For controlling how nested transactions behave.
+- traceLevel - Transaction trace level.
You can also specify the default values for some of these options in akka.conf. Here they are with their default values:
::
stm {
- max-retries = 1000
- timeout = 10
- write-skew = true
+ fair = on # Should global transactions be fair or non-fair (non fair yield better performance)
+ max-retries = 1000
+ timeout = 5 # Default timeout for blocking transactions and transaction set (in unit defined by
+ # the time-unit property)
+ write-skew = true
blocking-allowed = false
- interruptible = false
- speculative = true
- quick-release = true
- propagation = requires
- trace-level = none
+ interruptible = false
+ speculative = true
+ quick-release = true
+ propagation = "requires"
+ trace-level = "none"
}
You can also determine at which level a transaction factory is shared or not shared, which affects the way in which the STM can optimise transactions.
@@ -293,7 +313,7 @@ Here's a similar example with an individual transaction factory for each instanc
}
Transaction lifecycle listeners
--------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It's possible to have code that will only run on the successful commit of a transaction, or when a transaction aborts. You can do this by adding ``deferred`` or ``compensating`` blocks to a transaction.
@@ -311,7 +331,7 @@ It's possible to have code that will only run on the successful commit of a tran
}
Blocking transactions
----------------------
+^^^^^^^^^^^^^^^^^^^^^
You can block in a transaction until a condition is met by using an explicit ``retry``. To use ``retry`` you also need to configure the transaction to allow explicit retries.
@@ -322,23 +342,23 @@ Here is an example of using ``retry`` to block until an account has enough money
import akka.stm._
import akka.actor._
import akka.util.duration._
- import akka.util.Logging
+ import akka.event.EventHandler
type Account = Ref[Double]
case class Transfer(from: Account, to: Account, amount: Double)
- class Transferer extends Actor with Logging {
+ class Transferer extends Actor {
implicit val txFactory = TransactionFactory(blockingAllowed = true, trackReads = true, timeout = 60 seconds)
def receive = {
case Transfer(from, to, amount) =>
atomic {
if (from.get < amount) {
- log.info("not enough money - retrying")
+ EventHandler.info(this, "not enough money - retrying")
retry
}
- log.info("transferring")
+ EventHandler.info(this, "transferring")
from alter (_ - amount)
to alter (_ + amount)
}
@@ -365,7 +385,7 @@ Here is an example of using ``retry`` to block until an account has enough money
transferer.stop()
Alternative blocking transactions
----------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can also have two alternative blocking transactions, one of which can succeed first, with ``either-orElse``.
@@ -374,11 +394,11 @@ You can also have two alternative blocking transactions, one of which can succee
import akka.stm._
import akka.actor._
import akka.util.duration._
- import akka.util.Logging
+ import akka.event.EventHandler
case class Branch(left: Ref[Int], right: Ref[Int], amount: Int)
- class Brancher extends Actor with Logging {
+ class Brancher extends Actor {
implicit val txFactory = TransactionFactory(blockingAllowed = true, trackReads = true, timeout = 60 seconds)
def receive = {
@@ -386,13 +406,13 @@ You can also have two alternative blocking transactions, one of which can succee
atomic {
either {
if (left.get < amount) {
- log.info("not enough on left - retrying")
+ EventHandler.info(this, "not enough on left - retrying")
retry
}
log.info("going left")
} orElse {
if (right.get < amount) {
- log.info("not enough on right - retrying")
+ EventHandler.info(this, "not enough on right - retrying")
retry
}
log.info("going right")
@@ -416,14 +436,14 @@ You can also have two alternative blocking transactions, one of which can succee
brancher.stop()
-----
Transactional datastructures
-============================
+----------------------------
Akka provides two datastructures that are managed by the STM.
-* TransactionalMap
-* TransactionalVector
+
+- TransactionalMap
+- TransactionalVector
TransactionalMap and TransactionalVector look like regular mutable datastructures, they even implement the standard Scala 'Map' and 'RandomAccessSeq' interfaces, but they are implemented using persistent datastructures and managed references under the hood. Therefore they are safe to use in a concurrent environment. Underlying TransactionalMap is HashMap, an immutable Map but with near constant time access and modification operations. Similarly TransactionalVector uses a persistent Vector. See the Persistent Datastructures section below for more details.
@@ -492,25 +512,23 @@ Here is the same example using TransactionalMap:
}
// -> User("bill")
-----
Persistent datastructures
-=========================
+-------------------------
Akka's STM should only be used with immutable data. This can be costly if you have large datastructures and are using a naive copy-on-write. In order to make working with immutable datastructures fast enough Scala provides what are called Persistent Datastructures. There are currently two different ones:
-* HashMap (`scaladoc `_)
-* Vector (`scaladoc `_)
+* HashMap (`scaladoc `__)
+* Vector (`scaladoc `__)
They are immutable and each update creates a completely new version but they are using clever structural sharing in order to make them almost as fast, for both read and update, as regular mutable datastructures.
This illustration is taken from Rich Hickey's presentation. Copyright Rich Hickey 2009.
-``_
+.. image:: ../images/clojure-trees.png
-----
JTA integration
-===============
+---------------
The STM has JTA (Java Transaction API) integration. This means that it will, if enabled, hook in to JTA and start a JTA transaction when the STM transaction is started. It will also rollback the STM transaction if the JTA transaction has failed and vice versa. This does not mean that the STM is made durable, if you need that you should use one of the `persistence modules `_. It simply means that the STM will participate and interact with and external JTA provider, for example send a message using JMS atomically within an STM transaction, or use Hibernate to persist STM managed data etc.
@@ -536,9 +554,8 @@ You also have to configure which JTA provider to use etc in the 'jta' config sec
timeout = 60
}
-----
Ants simulation sample
-======================
+----------------------
One fun and very enlightening visual demo of STM, actors and transactional references is the `Ant simulation sample `_. I encourage you to run it and read through the code since it's a good example of using actors with STM.
diff --git a/akka-docs/scala/testing.rst b/akka-docs/scala/testing.rst
new file mode 100644
index 0000000000..9238cfd198
--- /dev/null
+++ b/akka-docs/scala/testing.rst
@@ -0,0 +1,334 @@
+#####################
+Testing Actor Systems
+#####################
+
+.. toctree::
+
+ testkit-example
+
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
+.. module:: akka-testkit
+ :synopsis: Tools for Testing Actor Systems
+.. moduleauthor:: Roland Kuhn
+.. versionadded:: 1.0
+.. versionchanged:: 1.1
+ added :class:`TestActorRef`
+
+As with any piece of software, automated tests are a very important part of the
+development cycle. The actor model presents a different view on how units of
+code are delimited and how they interact, which has an influence on how to
+perform tests.
+
+Akka comes with a dedicated module :mod:`akka-testkit` for supporting tests at
+different levels, which fall into two clearly distinct categories:
+
+ - Testing isolated pieces of code without involving the actor model, meaning
+ without multiple threads; this implies completely deterministic behavior
+ concerning the ordering of events and no concurrency concerns and will be
+ called **Unit Testing** in the following.
+ - Testing (multiple) encapsulated actors including multi-threaded scheduling;
+ this implies non-deterministic order of events but shielding from
+ concurrency concerns by the actor model and will be called **Integration
+ Testing** in the following.
+
+There are of course variations on the granularity of tests in both categories,
+where unit testing reaches down to white-box tests and integration testing can
+encompass functional tests of complete actor networks. The important
+distinction lies in whether concurrency concerns are part of the test or not.
+The tools offered are described in detail in the following sections.
+
+Unit Testing with :class:`TestActorRef`
+=======================================
+
+Testing the business logic inside :class:`Actor` classes can be divided into
+two parts: first, each atomic operation must work in isolation, then sequences
+of incoming events must be processed correctly, even in the presence of some
+possible variability in the ordering of events. The former is the primary use
+case for single-threaded unit testing, while the latter can only be verified in
+integration tests.
+
+Normally, the :class:`ActorRef` shields the underlying :class:`Actor` instance
+from the outside, the only communications channel is the actor's mailbox. This
+restriction is an impediment to unit testing, which led to the inception of the
+:class:`TestActorRef`. This special type of reference is designed specifically
+for test purposes and allows access to the actor in two ways: either by
+obtaining a reference to the underlying actor instance, or by invoking or
+querying the actor's behaviour (:meth:`receive`). Each one warrants its own
+section below.
+
+Obtaining a Reference to an :class:`Actor`
+------------------------------------------
+
+Having access to the actual :class:`Actor` object allows application of all
+traditional unit testing techniques on the contained methods. Obtaining a
+reference is done like this:
+
+.. code-block:: scala
+
+ val actorRef = TestActorRef[MyActor]
+ val actor = actorRef.underlyingActor
+
+Since :class:`TestActorRef` is generic in the actor type it returns the
+underlying actor with its proper static type. From this point on you may bring
+any unit testing tool to bear on your actor as usual.
+
+Testing the Actor's Behavior
+----------------------------
+
+When the dispatcher invokes the processing behavior of an actor on a message,
+it actually calls :meth:`apply` on the current behavior registered for the
+actor. This starts out with the return value of the declared :meth:`receive`
+method, but it may also be changed using :meth:`become` and :meth:`unbecome`,
+both of which have corresponding message equivalents, meaning that the behavior
+may be changed from the outside. All of this contributes to the overall actor
+behavior and it does not lend itself to easy testing on the :class:`Actor`
+itself. Therefore the :class:`TestActorRef` offers a different mode of
+operation to complement the :class:`Actor` testing: it supports all operations
+also valid on normal :class:`ActorRef`. Messages sent to the actor are
+processed synchronously on the current thread and answers may be sent back as
+usual. This trick is made possible by the :class:`CallingThreadDispatcher`
+described below; this dispatcher is set implicitly for any actor instantiated
+into a :class:`TestActorRef`.
+
+.. code-block:: scala
+
+ val actorRef = TestActorRef(new MyActor)
+ val result = actorRef !! msg
+ result must be (expected)
+
+As the :class:`TestActorRef` is a subclass of :class:`LocalActorRef` with a few
+special extras, also aspects like linking to a supervisor and restarting work
+properly, as long as all actors involved use the
+:class:`CallingThreadDispatcher`. As soon as you add elements which include
+more sophisticated scheduling you leave the realm of unit testing as you then
+need to think about proper synchronization again (in most cases the problem of
+waiting until the desired effect had a chance to happen).
+
+One more special aspect which is overridden for single-threaded tests is the
+:meth:`receiveTimeout`, as including that would entail asynchronous queuing of
+:obj:`ReceiveTimeout` messages, violating the synchronous contract.
+
+.. warning::
+
+ To summarize: :class:`TestActorRef` overwrites two fields: it sets the
+ dispatcher to :obj:`CallingThreadDispatcher.global` and it sets the
+ :obj:`receiveTimeout` to zero.
+
+The Way In-Between
+------------------
+
+If you want to test the actor behavior, including hotswapping, but without
+involving a dispatcher and without having the :class:`TestActorRef` swallow
+any thrown exceptions, then there is another mode available for you: just use
+the :class:`TestActorRef` as a partial function, the calls to
+:meth:`isDefinedAt` and :meth:`apply` will be forwarded to the underlying
+actor:
+
+.. code-block:: scala
+
+ val ref = TestActorRef[MyActor]
+ ref.isDefinedAt('unknown) must be (false)
+ intercept[IllegalActorStateException] { ref(RequestReply) }
+
+Use Cases
+---------
+
+You may of course mix and match both modi operandi of :class:`TestActorRef` as
+suits your test needs:
+
+ - one common use case is setting up the actor into a specific internal state
+ before sending the test message
+ - another is to verify correct internal state transitions after having sent
+ the test message
+
+Feel free to experiment with the possibilities, and if you find useful
+patterns, don't hesitate to let the Akka forums know about them! Who knows,
+common operations might even be worked into nice DSLs.
+
+Integration Testing with :class:`TestKit`
+=========================================
+
+When you are reasonably sure that your actor's business logic is correct, the
+next step is verifying that it works correctly within its intended environment
+(if the individual actors are simple enough, possibly because they use the
+:mod:`FSM` module, this might also be the first step). The definition of the
+environment depends of course very much on the problem at hand and the level at
+which you intend to test, ranging for functional/integration tests to full
+system tests. The minimal setup consists of the test procedure, which provides
+the desired stimuli, the actor under test, and an actor receiving replies.
+Bigger systems replace the actor under test with a network of actors, apply
+stimuli at varying injection points and arrange results to be sent from
+different emission points, but the basic principle stays the same in that a
+single procedure drives the test.
+
+The :class:`TestKit` trait contains a collection of tools which makes this
+common task easy:
+
+.. code-block:: scala
+
+ class MySpec extends WordSpec with MustMatchers with TestKit {
+
+ "An Echo actor" must {
+
+ "send back messages unchanged" in {
+
+ val echo = Actor.actorOf[EchoActor].start()
+ echo ! "hello world"
+ expectMsg("hello world")
+
+ }
+
+ }
+
+ }
+
+The :class:`TestKit` contains an actor named :obj:`testActor` which is
+implicitly used as sender reference when dispatching messages from the test
+procedure. This enables replies to be received by this internal actor, whose
+only function is to queue them so that interrogation methods like
+:meth:`expectMsg` can examine them. The :obj:`testActor` may also be passed to
+other actors as usual, usually subscribing it as notification listener. There
+is a whole set of examination methods, e.g. receiving all consecutive messages
+matching certain criteria, receiving a whole sequence of fixed messages or
+classes, receiving nothing for some time, etc.
+
+.. note::
+
+ The test actor shuts itself down by default after 5 seconds (configurable)
+ of inactivity, relieving you of the duty of explicitly managing it.
+
+Another important part of functional testing concerns timing: certain events
+must not happen immediately (like a timer), others need to happen before a
+deadline. Therefore, all examination methods accept an upper time limit within
+the positive or negative result must be obtained. Lower time limits need to be
+checked external to the examination, which is facilitated by a new construct
+for managing time constraints:
+
+.. code-block:: scala
+
+ within([min, ]max) {
+ ...
+ }
+
+The block given to :meth:`within` must complete after a :ref:`Duration` which
+is between :obj:`min` and :obj:`max`, where the former defaults to zero. The
+deadline calculated by adding the :obj:`max` parameter to the block's start
+time is implicitly available within the block to all examination methods, if
+you do not specify it, is is inherited from the innermost enclosing
+:meth:`within` block. It should be noted that using :meth:`expectNoMsg` will
+terminate upon reception of a message or at the deadline, whichever occurs
+first; it follows that this examination usually is the last statement in a
+:meth:`within` block.
+
+.. code-block:: scala
+
+ class SomeSpec extends WordSpec with MustMatchers with TestKit {
+ "A Worker" must {
+ "send timely replies" in {
+ val worker = actorOf(...)
+ within (50 millis) {
+ worker ! "some work"
+ expectMsg("some result")
+ expectNoMsg
+ }
+ }
+ }
+ }
+
+Ray Roestenburg has written a great article on using the TestKit:
+``_.
+His full example is also available :ref:`here `.
+
+CallingThreadDispatcher
+=======================
+
+The :class:`CallingThreadDispatcher` serves good purposes in unit testing, as
+described above, but originally it was conceived in order to allow contiguous
+stack traces to be generated in case of an error. As this special dispatcher
+runs everything which would normally be queued directly on the current thread,
+the full history of a message's processing chain is recorded on the call stack,
+so long as all intervening actors run on this dispatcher.
+
+How it works
+------------
+
+When receiving an invocation, the :class:`CallingThreadDispatcher` checks
+whether the receiving actor is already active on the current thread. The
+simplest example for this situation is an actor which sends a message to
+itself. In this case, processing cannot continue immediately as that would
+violate the actor model, so the invocation is queued and will be processed when
+the active invocation on that actor finishes its processing; thus, it will be
+processed on the calling thread, but simply after the actor finishes its
+previous work. In the other case, the invocation is simply processed
+immediately on the current thread. Futures scheduled via this dispatcher are
+also executed immediately.
+
+This scheme makes the :class:`CallingThreadDispatcher` work like a general
+purpose dispatcher for any actors which never block on external events.
+
+In the presence of multiple threads it may happen that two invocations of an
+actor running on this dispatcher happen on two different threads at the same
+time. In this case, both will be processed directly on their respective
+threads, where both compete for the actor's lock and the loser has to wait.
+Thus, the actor model is left intact, but the price is loss of concurrency due
+to limited scheduling. In a sense this is equivalent to traditional mutex style
+concurrency.
+
+The other remaining difficulty is correct handling of suspend and resume: when
+an actor is suspended, subsequent invocations will be queued in thread-local
+queues (the same ones used for queuing in the normal case). The call to
+:meth:`resume`, however, is done by one specific thread, and all other threads
+in the system will probably not be executing this specific actor, which leads
+to the problem that the thread-local queues cannot be emptied by their native
+threads. Hence, the thread calling :meth:`resume` will collect all currently
+queued invocations from all threads into its own queue and process them.
+
+Limitations
+-----------
+
+If an actor's behavior blocks on a something which would normally be affected
+by the calling actor after having sent the message, this will obviously
+dead-lock when using this dispatcher. This is a common scenario in actor tests
+based on :class:`CountDownLatch` for synchronization:
+
+.. code-block:: scala
+
+ val latch = new CountDownLatch(1)
+ actor ! startWorkAfter(latch) // actor will call latch.await() before proceeding
+ doSomeSetupStuff()
+ latch.countDown()
+
+The example would hang indefinitely within the message processing initiated on
+the second line and never reach the fourth line, which would unblock it on a
+normal dispatcher.
+
+Thus, keep in mind that the :class:`CallingThreadDispatcher` is not a
+general-purpose replacement for the normal dispatchers. On the other hand it
+may be quite useful to run your actor network on it for testing, because if it
+runs without dead-locking chances are very high that it will not dead-lock in
+production.
+
+.. warning::
+
+ The above sentence is unfortunately not a strong guarantee, because your
+ code might directly or indirectly change its behavior when running on a
+ different dispatcher. If you are looking for a tool to help you debug
+ dead-locks, the :class:`CallingThreadDispatcher` may help with certain error
+ scenarios, but keep in mind that it has may give false negatives as well as
+ false positives.
+
+Benefits
+--------
+
+To summarize, these are the features with the :class:`CallingThreadDispatcher`
+has to offer:
+
+ - Deterministic execution of single-threaded tests while retaining nearly full
+ actor semantics
+ - Full message processing history leading up to the point of failure in
+ exception stack traces
+ - Exclusion of certain classes of dead-lock scenarios
+
diff --git a/akka-docs/scala/testkit-example.rst b/akka-docs/scala/testkit-example.rst
new file mode 100644
index 0000000000..f53543e474
--- /dev/null
+++ b/akka-docs/scala/testkit-example.rst
@@ -0,0 +1,145 @@
+.. _testkit-example:
+
+###############
+TestKit Example
+###############
+
+Ray Roestenburg's example code from `his blog `_.
+
+.. code-block:: scala
+
+ package unit.akka
+
+ import org.scalatest.matchers.ShouldMatchers
+ import org.scalatest.{WordSpec, BeforeAndAfterAll}
+ import akka.actor.Actor._
+ import akka.util.duration._
+ import akka.util.TestKit
+ import java.util.concurrent.TimeUnit
+ import akka.actor.{ActorRef, Actor}
+ import util.Random
+
+ /**
+ * a Test to show some TestKit examples
+ */
+
+ class TestKitUsageSpec extends WordSpec with BeforeAndAfterAll with ShouldMatchers with TestKit {
+ val echoRef = actorOf(new EchoActor).start()
+ val forwardRef = actorOf(new ForwardingActor(testActor)).start()
+ val filterRef = actorOf(new FilteringActor(testActor)).start()
+ val randomHead = Random.nextInt(6)
+ val randomTail = Random.nextInt(10)
+ val headList = List().padTo(randomHead, "0")
+ val tailList = List().padTo(randomTail, "1")
+ val seqRef = actorOf(new SequencingActor(testActor, headList, tailList)).start()
+
+ override protected def afterAll(): scala.Unit = {
+ stopTestActor
+ echoRef.stop()
+ forwardRef.stop()
+ filterRef.stop()
+ seqRef.stop()
+ }
+
+ "An EchoActor" should {
+ "Respond with the same message it receives" in {
+ within(100 millis) {
+ echoRef ! "test"
+ expectMsg("test")
+ }
+ }
+ }
+ "A ForwardingActor" should {
+ "Forward a message it receives" in {
+ within(100 millis) {
+ forwardRef ! "test"
+ expectMsg("test")
+ }
+ }
+ }
+ "A FilteringActor" should {
+ "Filter all messages, except expected messagetypes it receives" in {
+ var messages = List[String]()
+ within(100 millis) {
+ filterRef ! "test"
+ expectMsg("test")
+ filterRef ! 1
+ expectNoMsg
+ filterRef ! "some"
+ filterRef ! "more"
+ filterRef ! 1
+ filterRef ! "text"
+ filterRef ! 1
+
+ receiveWhile(500 millis) {
+ case msg: String => messages = msg :: messages
+ }
+ }
+ messages.length should be(3)
+ messages.reverse should be(List("some", "more", "text"))
+ }
+ }
+ "A SequencingActor" should {
+ "receive an interesting message at some point " in {
+ within(100 millis) {
+ seqRef ! "something"
+ ignoreMsg {
+ case msg: String => msg != "something"
+ }
+ expectMsg("something")
+ ignoreMsg {
+ case msg: String => msg == "1"
+ }
+ expectNoMsg
+ }
+ }
+ }
+ }
+
+ /**
+ * An Actor that echoes everything you send to it
+ */
+ class EchoActor extends Actor {
+ def receive = {
+ case msg => {
+ self.reply(msg)
+ }
+ }
+ }
+
+ /**
+ * An Actor that forwards every message to a next Actor
+ */
+ class ForwardingActor(next: ActorRef) extends Actor {
+ def receive = {
+ case msg => {
+ next ! msg
+ }
+ }
+ }
+
+ /**
+ * An Actor that only forwards certain messages to a next Actor
+ */
+ class FilteringActor(next: ActorRef) extends Actor {
+ def receive = {
+ case msg: String => {
+ next ! msg
+ }
+ case _ => None
+ }
+ }
+
+ /**
+ * An actor that sends a sequence of messages with a random head list, an interesting value and a random tail list
+ * The idea is that you would like to test that the interesting value is received and that you cant be bothered with the rest
+ */
+ class SequencingActor(next: ActorRef, head: List[String], tail: List[String]) extends Actor {
+ def receive = {
+ case msg => {
+ head map (next ! _)
+ next ! msg
+ tail map (next ! _)
+ }
+ }
+ }
diff --git a/akka-docs/pending/transactors-scala.rst b/akka-docs/scala/transactors.rst
similarity index 87%
rename from akka-docs/pending/transactors-scala.rst
rename to akka-docs/scala/transactors.rst
index 454fffb6a6..e4ee824cd3 100644
--- a/akka-docs/pending/transactors-scala.rst
+++ b/akka-docs/scala/transactors.rst
@@ -1,10 +1,16 @@
-**Transactors (Scala)**
-=============================================================
+.. _transactors-scala:
+
+Transactors (Scala)
+===================
+
+.. sidebar:: Contents
+
+ .. contents:: :local:
Module stability: **SOLID**
Why Transactors?
-================
+----------------
Actors are excellent for solving problems where you have many independent processes that can work in isolation and only interact with other Actors through message passing. This model fits many problems. But the actor model is unfortunately a terrible model for implementing truly shared state. E.g. when you need to have consensus and a stable view of state across many components. The classic example is the bank account where clients can deposit and withdraw, in which each operation needs to be atomic. For detailed discussion on the topic see `this JavaOne presentation `_.
@@ -15,21 +21,21 @@ Akka's Transactors combine Actors and STM to provide the best of the Actor model
If you need Durability then you should not use one of the in-memory data structures but one of the persistent ones.
Generally, the STM is not needed very often when working with Akka. Some use-cases (that we can think of) are:
-# When you really need composable message flows across many actors updating their **internal local** state but need them to do that atomically in one big transaction. Might not often, but when you do need this then you are screwed without it.
-# When you want to share a datastructure across actors.
-# When you need to use the persistence modules.
+
+- When you really need composable message flows across many actors updating their **internal local** state but need them to do that atomically in one big transaction. Might not often, but when you do need this then you are screwed without it.
+- When you want to share a datastructure across actors.
+- When you need to use the persistence modules.
Actors and STM
---------------
+^^^^^^^^^^^^^^
You can combine Actors and STM in several ways. An Actor may use STM internally so that particular changes are guaranteed to be atomic. Actors may also share transactional datastructures as the STM provides safe shared state across threads.
It's also possible to coordinate transactions across Actors or threads so that either the transactions in a set all commit successfully or they all fail. This is the focus of Transactors and the explicit support for coordinated transactions in this section.
-----
Coordinated transactions
-========================
+------------------------
Akka provides an explicit mechanism for coordinating transactions across Actors. Under the hood it uses a ``CountDownCommitBarrier``, similar to a CountDownLatch.
@@ -70,7 +76,7 @@ Here is an example of coordinating two simple counter Actors so that they both i
counter1.stop()
counter2.stop()
-To start a new coordinated transaction set that you will also participate in, just create a ``Coordinated`` object:
+To start a new coordinated transaction that you will also participate in, just create a ``Coordinated`` object:
.. code-block:: scala
@@ -90,7 +96,7 @@ To receive a coordinated message in an actor simply match it in a case statement
case coordinated @ Coordinated(Message) => ...
}
-To include another actor in the same coordinated transaction set that you've created or received, use the apply method on that object. This will increment the number of parties involved by one and create a new ``Coordinated`` object to be sent.
+To include another actor in the same coordinated transaction that you've created or received, use the apply method on that object. This will increment the number of parties involved by one and create a new ``Coordinated`` object to be sent.
.. code-block:: scala
@@ -106,10 +112,9 @@ To enter the coordinated transaction use the atomic method of the coordinated ob
The coordinated transaction will wait for the other transactions before committing. If any of the coordinated transactions fail then they all fail.
-----
Transactor
-==========
+----------
Transactors are actors that provide a general pattern for coordinating transactions, using the explicit coordination described above.
@@ -125,7 +130,7 @@ Here's an example of a simple transactor that will join a coordinated transactio
class Counter extends Transactor {
val count = Ref(0)
- def atomically = {
+ override def atomically = {
case Increment => count alter (_ + 1)
}
}
@@ -140,6 +145,7 @@ Example of coordinating an increment:
import akka.transactor.Transactor
import akka.stm.Ref
+ import akka.actor.ActorRef
case object Increment
@@ -150,7 +156,7 @@ Example of coordinating an increment:
case Increment => include(friend)
}
- def atomically = {
+ override def atomically = {
case Increment => count alter (_ + 1)
}
}
@@ -172,14 +178,13 @@ Using ``sendTo`` to coordinate transactions but pass-on a different message than
case SomeMessage => sendTo(actor1 -> Message1, actor2 -> Message2)
}
-To exeucte directly before or after the coordinated transaction, override the ``before`` and ``after`` methods. These methods also expect partial functions like the receive method. They do not execute within the transaction.
+To execute directly before or after the coordinated transaction, override the ``before`` and ``after`` methods. These methods also expect partial functions like the receive method. They do not execute within the transaction.
To completely bypass coordinated transactions override the ``normally`` method. Any message matched by ``normally`` will not be matched by the other methods, and will not be involved in coordinated transactions. In this method you can implement normal actor behavior, or use the normal STM atomic for local transactions.
-----
Coordinating Typed Actors
-=========================
+-------------------------
It's also possible to use coordinated transactions with typed actors. You can explicitly pass around ``Coordinated`` objects, or use built-in support with the ``@Coordinated`` annotation and the ``Coordination.coordinate`` method.
@@ -188,7 +193,7 @@ To specify a method should use coordinated transactions add the ``@Coordinated``
.. code-block:: scala
trait Counter {
- @Coordinated def increment: Unit
+ @Coordinated def increment()
def get: Int
}
@@ -197,8 +202,8 @@ To coordinate transactions use a ``coordinate`` block:
.. code-block:: scala
coordinate {
- counter1.increment
- counter2.increment
+ counter1.increment()
+ counter2.increment()
}
Here's an example of using ``@Coordinated`` with a TypedActor to coordinate increments.
@@ -211,13 +216,13 @@ Here's an example of using ``@Coordinated`` with a TypedActor to coordinate incr
import akka.transactor.Coordination._
trait Counter {
- @Coordinated def increment: Unit
+ @Coordinated def increment()
def get: Int
}
class CounterImpl extends TypedActor with Counter {
val ref = Ref(0)
- def increment = ref alter (_ + 1)
+ def increment() { ref alter (_ + 1) }
def get = ref.get
}
@@ -227,8 +232,8 @@ Here's an example of using ``@Coordinated`` with a TypedActor to coordinate incr
val counter2 = TypedActor.newInstance(classOf[Counter], classOf[CounterImpl])
coordinate {
- counter1.increment
- counter2.increment
+ counter1.increment()
+ counter2.increment()
}
TypedActor.stop(counter1)
@@ -236,9 +241,10 @@ Here's an example of using ``@Coordinated`` with a TypedActor to coordinate incr
The ``coordinate`` block will wait for the transactions to complete. If you do not want to wait then you can specify this explicitly:
-``_
-coordinate(wait = false) {
- counter1.increment
- counter2.increment
-}
-``_
+.. code-block:: scala
+
+ coordinate(wait = false) {
+ counter1.increment()
+ counter2.increment()
+ }
+
diff --git a/akka-docs/pending/tutorial-chat-server-scala.rst b/akka-docs/scala/tutorial-chat-server.rst
similarity index 92%
rename from akka-docs/pending/tutorial-chat-server-scala.rst
rename to akka-docs/scala/tutorial-chat-server.rst
index 9d35abddd9..daa28d2ca3 100644
--- a/akka-docs/pending/tutorial-chat-server-scala.rst
+++ b/akka-docs/scala/tutorial-chat-server.rst
@@ -1,6 +1,10 @@
-Tutorial: write a scalable, fault-tolerant, persistent network chat server and client (Scala)
+Tutorial: write a scalable, fault-tolerant, network chat server and client (Scala)
=============================================================================================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Introduction
------------
@@ -44,6 +48,8 @@ Here is a little example before we dive into a more interesting one.
.. code-block:: scala
+ import akka.actor.Actor
+
class MyActor extends Actor {
def receive = {
case "test" => println("received test")
@@ -81,12 +87,53 @@ We will try to write a simple chat/IM system. It is client-server based and uses
We will use many of the features of Akka along the way. In particular; Actors, fault-tolerance using Actor supervision, remote Actors, Software Transactional Memory (STM) and persistence.
-But let's start by defining the messages that will flow in our system.
+Creating an Akka SBT project
+----------------------------
+
+First we need to create an SBT project for our tutorial. You do that by stepping into the directory you want to create your project in and invoking the ``sbt`` command answering the questions for setting up your project::
+
+ $ sbt
+ Project does not exist, create new project? (y/N/s) y
+ Name: Chat
+ Organization: Hakkers Inc
+ Version [1.0]:
+ Scala version [2.9.0.RC1]:
+ sbt version [0.7.6.RC0]:
+
+Add the Akka SBT plugin definition to your SBT project by creating a ``Plugins.scala`` file in the ``project/plugins`` directory containing::
+
+ import sbt._
+
+ class Plugins(info: ProjectInfo) extends PluginDefinition(info) {
+ val akkaRepo = "Akka Repo" at "http://akka.io/repository"
+ val akkaPlugin = "se.scalablesolutions.akka" % "akka-sbt-plugin" % "1.1-M1"
+ }
+
+Create a project definition ``project/build/Project.scala`` file containing::
+
+ import sbt._
+
+ class ChatProject(info: ProjectInfo) extends DefaultProject(info) with AkkaProject {
+ val akkaRepo = "Akka Repo" at "http://akka.io/repository"
+ val akkaSTM = akkaModule("stm")
+ val akkaRemote = akkaModule("remote")
+ }
+
+
+Make SBT download the dependencies it needs. That is done by invoking::
+
+ > reload
+ > update
+
+From the SBT project you can generate files for your IDE:
+
+- `SbtEclipsify `_ to generate Eclipse project. Detailed instructions are available in :ref:`getting-started-first-scala-eclipse`.
+- `sbt-idea `_ to generate IntelliJ IDEA project.
Creating messages
-----------------
-It is very important that all messages that will be sent around in the system are immutable. The Actor model relies on the simple fact that no state is shared between Actors and the only way to guarantee that is to make sure we don't pass mutable state around as part of the messages.
+Let's start by defining the messages that will flow in our system. It is very important that all messages that will be sent around in the system are immutable. The Actor model relies on the simple fact that no state is shared between Actors and the only way to guarantee that is to make sure we don't pass mutable state around as part of the messages.
In Scala we have something called `case classes `_. These make excellent messages since they are both immutable and great to pattern match on.
@@ -118,7 +165,8 @@ Sometimes however, there is a need for sequential logic, sending a message and w
def login = chat ! Login(name)
def logout = chat ! Logout(name)
def post(message: String) = chat ! ChatMessage(name, name + ": " + message)
- def chatLog = (chat !! GetChatLog(name)).as[ChatLog].getOrElse(throw new Exception("Couldn't get the chat log from ChatServer"))
+ def chatLog = (chat !! GetChatLog(name)).as[ChatLog]
+ .getOrElse(throw new Exception("Couldn't get the chat log from ChatServer"))
}
As you can see, we are using the 'Actor.remote.actorFor' to lookup the chat server on the remote node. From this call we will get a handle to the remote instance and can use it as it is local.
@@ -221,7 +269,7 @@ I'll try to show you how we can make use Scala's mixins to decouple the Actor im
protected def sessionManagement: Receive
protected def shutdownSessions(): Unit
- override def postStop = {
+ override def postStop() = {
EventHandler.info(this, "Chat server is shutting down...")
shutdownSessions
self.unlink(storage)
@@ -358,7 +406,7 @@ It responds to two different messages; 'ChatMessage' and 'GetChatLog'. The 'Chat
The 'GetChatLog' message handler retrieves all the messages in the chat log storage inside an atomic block, iterates over them using the 'map' combinator transforming them from 'Array[Byte] to 'String'. Then it invokes the 'reply(message)' function that will send the chat log to the original sender; the 'ChatClient'.
-You might rememeber that the 'ChatServer' was supervising the 'ChatStorage' actor. When we discussed that we showed you the supervising Actor's view. Now is the time for the supervised Actor's side of things. First, a supervised Actor need to define a life-cycle in which it declares if it should be seen as a:
+You might remember that the 'ChatServer' was supervising the 'ChatStorage' actor. When we discussed that we showed you the supervising Actor's view. Now is the time for the supervised Actor's side of things. First, a supervised Actor need to define a life-cycle in which it declares if it should be seen as a:
* 'Permanent': which means that the actor will always be restarted.
* 'Temporary': which means that the actor will not be restarted, but it will be shut down through the regular shutdown process so the 'postStop' callback function will called.
@@ -422,7 +470,7 @@ We have now created the full functionality for the chat server, all nicely decou
SessionManagement with
ChatManagement with
MemoryChatStorageFactory {
- override def preStart = {
+ override def preStart() = {
remote.start("localhost", 2552);
remote.register("chat:service", self) //Register the actor with the specified service id
}
diff --git a/akka-docs/pending/typed-actors-scala.rst b/akka-docs/scala/typed-actors.rst
similarity index 91%
rename from akka-docs/pending/typed-actors-scala.rst
rename to akka-docs/scala/typed-actors.rst
index 3d03cc93b1..74c7f22f1f 100644
--- a/akka-docs/pending/typed-actors-scala.rst
+++ b/akka-docs/scala/typed-actors.rst
@@ -1,6 +1,10 @@
Typed Actors (Scala)
====================
+.. sidebar:: Contents
+
+ .. contents:: :local:
+
Module stability: **SOLID**
The Typed Actors are implemented through `Typed Actors `_. It uses AOP through `AspectWerkz `_ to turn regular POJOs into asynchronous non-blocking Actors with semantics of the Actor Model. E.g. each message dispatch is turned into a message that is put on a queue to be processed by the Typed Actor sequentially one by one.
@@ -66,6 +70,7 @@ Configuration factory class
Using a configuration object:
.. code-block:: scala
+
import akka.actor.TypedActorConfiguration
import akka.util.Duration
import akka.util.duration._
@@ -95,7 +100,7 @@ Methods that return void are turned into ‘fire-and-forget’ semantics by asyn
Request-reply message send
^^^^^^^^^^^^^^^^^^^^^^^^^^
-Methods that return something (e.g. non-void methods) are turned into ‘send-and-recieve-eventually’ semantics by asynchronously firing off the message and wait on the reply using a Future.
+Methods that return something (e.g. non-void methods) are turned into ‘send-and-receive-eventually’ semantics by asynchronously firing off the message and wait on the reply using a Future.
.. code-block:: scala
@@ -111,7 +116,7 @@ Generally it is preferred to use fire-forget messages as much as possible since
Request-reply-with-future message send
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Methods that return a 'akka.dispatch.Future' are turned into ‘send-and-recieve-with-future’ semantics by asynchronously firing off the message and returns immediately with a Future. You need to use the 'future(...)' method in the TypedActor base class to resolve the Future that the client code is waiting on.
+Methods that return a 'akka.dispatch.Future' are turned into ‘send-and-receive-with-future’ semantics by asynchronously firing off the message and returns immediately with a Future. You need to use the 'future(...)' method in the TypedActor base class to resolve the Future that the client code is waiting on.
Here is an example:
@@ -163,9 +168,21 @@ Here is an example how you can use it to in a 'void' (e.g. fire-forget) method t
}
}
-If the sender, sender future etc. is not available, then these methods will return 'null' so you should have a way of dealing with scenario.
+If the sender, sender future etc. is not available, then these methods will return 'null' so you should have a way of dealing with that scenario.
Messages and immutability
-------------------------
**IMPORTANT**: Messages can be any kind of object but have to be immutable (there is a workaround, see next section). Java or Scala can’t enforce immutability (yet) so this has to be by convention. Primitives like String, int, Long are always immutable. Apart from these you have to create your own immutable objects to send as messages. If you pass on a reference to an instance that is mutable then this instance can be modified concurrently by two different Typed Actors and the Actor model is broken leaving you with NO guarantees and most likely corrupt data.
+
+Akka can help you in this regard. It allows you to turn on an option for serializing all messages, e.g. all parameters to the Typed Actor effectively making a deep clone/copy of the parameters. This will make sending mutable messages completely safe. This option is turned on in the ‘$AKKA_HOME/config/akka.conf’ config file like this:
+
+.. code-block:: ruby
+
+ akka {
+ actor {
+ serialize-messages = on # does a deep clone of messages to ensure immutability
+ }
+ }
+
+This will make a deep clone (using Java serialization) of all parameters.
diff --git a/akka-http/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyWriter_FIXME b/akka-http/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyWriter_FIXME
deleted file mode 100644
index 51bc8cccd2..0000000000
--- a/akka-http/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyWriter_FIXME
+++ /dev/null
@@ -1 +0,0 @@
-se.scalablesolutions.akka.rest.ListWriter
diff --git a/akka-http/src/main/scala/akka/http/Mist.scala b/akka-http/src/main/scala/akka/http/Mist.scala
index 379cbfb36d..99e717281a 100644
--- a/akka-http/src/main/scala/akka/http/Mist.scala
+++ b/akka-http/src/main/scala/akka/http/Mist.scala
@@ -269,7 +269,7 @@ class RootEndpoint extends Actor with Endpoint {
// adopt the configured id
if (RootActorBuiltin) self.id = RootActorID
- override def preStart =
+ override def preStart() =
_attachments = Tuple2((uri: String) => {uri eq Root}, (uri: String) => this.actor) :: _attachments
def recv: Receive = {
diff --git a/akka-http/src/main/scala/akka/security/Security.scala b/akka-http/src/main/scala/akka/security/Security.scala
index dce249de46..7789164fd3 100644
--- a/akka-http/src/main/scala/akka/security/Security.scala
+++ b/akka-http/src/main/scala/akka/security/Security.scala
@@ -182,7 +182,7 @@ trait AuthenticationActor[C <: Credentials] extends Actor {
* Responsible for the execution flow of authentication
*
* Credentials are extracted and verified from the request,
- * and a se3curity context is created for the ContainerRequest
+ * and a security context is created for the ContainerRequest
* this should ensure good integration with current Jersey security
*/
protected val authenticate: Receive = {
diff --git a/akka-http/src/test/scala/config/ConfigSpec.scala b/akka-http/src/test/scala/config/ConfigSpec.scala
index 3adea2fc43..2b21f3cc34 100644
--- a/akka-http/src/test/scala/config/ConfigSpec.scala
+++ b/akka-http/src/test/scala/config/ConfigSpec.scala
@@ -19,7 +19,7 @@ class ConfigSpec extends WordSpec with MustMatchers {
getString("akka.http.authenticator") must equal(Some("N/A"))
getBool("akka.http.connection-close") must equal(Some(true))
getString("akka.http.expired-header-name") must equal(Some("Async-Timeout"))
- getList("akka.http.filters") must equal(List("se.scalablesolutions.akka.security.AkkaSecurityFilterFactory"))
+ getList("akka.http.filters") must equal(List("akka.security.AkkaSecurityFilterFactory"))
getList("akka.http.resource-packages") must equal(Nil)
getString("akka.http.hostname") must equal(Some("localhost"))
getString("akka.http.expired-header-value") must equal(Some("expired"))
diff --git a/akka-remote/src/main/scala/akka/remote/BootableRemoteActorService.scala b/akka-remote/src/main/scala/akka/remote/BootableRemoteActorService.scala
index 8139b35d0b..aa88be92c0 100644
--- a/akka-remote/src/main/scala/akka/remote/BootableRemoteActorService.scala
+++ b/akka-remote/src/main/scala/akka/remote/BootableRemoteActorService.scala
@@ -20,18 +20,18 @@ trait BootableRemoteActorService extends Bootable {
def run = Actor.remote.start(self.applicationLoader.getOrElse(null)) //Use config host/port
}, "Akka Remote Service")
- def startRemoteService = remoteServerThread.start()
+ def startRemoteService() { remoteServerThread.start() }
- abstract override def onLoad = {
+ abstract override def onLoad() {
if (ReflectiveAccess.isRemotingEnabled && RemoteServerSettings.isRemotingEnabled) {
- startRemoteService
+ startRemoteService()
}
- super.onLoad
+ super.onLoad()
}
- abstract override def onUnload = {
- Actor.remote.shutdown
+ abstract override def onUnload() {
+ Actor.remote.shutdown()
if (remoteServerThread.isAlive) remoteServerThread.join(1000)
- super.onUnload
+ super.onUnload()
}
}
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 8781c72ecd..7caea56e88 100644
--- a/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala
+++ b/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala
@@ -41,7 +41,7 @@ import java.util.concurrent.atomic.{AtomicReference, AtomicBoolean}
import java.util.concurrent._
import akka.AkkaException
-class RemoteClientMessageBufferException(message: String) extends AkkaException(message)
+class RemoteClientMessageBufferException(message: String, cause: Throwable = null) extends AkkaException(message, cause)
object RemoteEncoder {
def encode(rmp: RemoteMessageProtocol): AkkaRemoteProtocol = {
@@ -107,7 +107,7 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem
def shutdownClientConnection(address: InetSocketAddress): Boolean = lock withWriteGuard {
remoteClients.remove(Address(address)) match {
- case s: Some[RemoteClient] => s.get.shutdown
+ case s: Some[RemoteClient] => s.get.shutdown()
case None => false
}
}
@@ -132,15 +132,15 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem
/**
* Clean-up all open connections.
*/
- def shutdownClientModule = {
- shutdownRemoteClients
+ def shutdownClientModule() {
+ shutdownRemoteClients()
//TODO: Should we empty our remoteActors too?
//remoteActors.clear
}
- def shutdownRemoteClients = lock withWriteGuard {
- remoteClients.foreach({ case (addr, client) => client.shutdown })
- remoteClients.clear
+ def shutdownRemoteClients() = lock withWriteGuard {
+ remoteClients.foreach({ case (addr, client) => client.shutdown() })
+ remoteClients.clear()
}
def registerClientManagedActor(hostname: String, port: Int, uuid: Uuid) = {
@@ -155,7 +155,7 @@ trait NettyRemoteClientModule extends RemoteClientModule { self: ListenerManagem
/**
* This is the abstract baseclass for netty remote clients, currently there's only an
- * ActiveRemoteClient, but otehrs could be feasible, like a PassiveRemoteClient that
+ * ActiveRemoteClient, but others could be feasible, like a PassiveRemoteClient that
* reuses an already established connection.
*/
abstract class RemoteClient private[akka] (
@@ -187,7 +187,7 @@ abstract class RemoteClient private[akka] (
def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean
- def shutdown: Boolean
+ def shutdown(): Boolean
/**
* Returns an array with the current pending messages not yet delivered.
@@ -403,16 +403,16 @@ class ActiveRemoteClient private[akka] (
}
//Please note that this method does _not_ remove the ARC from the NettyRemoteClientModule's map of clients
- def shutdown = runSwitch switchOff {
+ def shutdown() = runSwitch switchOff {
notifyListeners(RemoteClientShutdown(module, remoteAddress))
timer.stop()
timer = null
openChannels.close.awaitUninterruptibly
openChannels = null
- bootstrap.releaseExternalResources
+ bootstrap.releaseExternalResources()
bootstrap = null
connection = null
- pendingRequests.clear
+ pendingRequests.clear()
}
private[akka] def isWithinReconnectionTimeWindow: Boolean = {
@@ -629,7 +629,7 @@ class NettyRemoteServer(serverModule: NettyRemoteServerModule, val host: String,
openChannels.add(bootstrap.bind(address))
serverModule.notifyListeners(RemoteServerStarted(serverModule))
- def shutdown {
+ def shutdown() {
try {
val shutdownSignal = {
val b = RemoteControlProtocol.newBuilder
@@ -641,7 +641,7 @@ class NettyRemoteServer(serverModule: NettyRemoteServerModule, val host: String,
openChannels.write(RemoteEncoder.encode(shutdownSignal)).awaitUninterruptibly
openChannels.disconnect
openChannels.close.awaitUninterruptibly
- bootstrap.releaseExternalResources
+ bootstrap.releaseExternalResources()
serverModule.notifyListeners(RemoteServerShutdown(serverModule))
} catch {
case e: Exception =>
@@ -684,11 +684,11 @@ trait NettyRemoteServerModule extends RemoteServerModule { self: RemoteModule =>
this
}
- def shutdownServerModule = guard withGuard {
+ def shutdownServerModule() = guard withGuard {
_isRunning switchOff {
currentServer.getAndSet(None) foreach {
instance =>
- instance.shutdown
+ instance.shutdown()
}
}
}
diff --git a/akka-remote/src/test/scala/remote/AkkaRemoteTest.scala b/akka-remote/src/test/scala/remote/AkkaRemoteTest.scala
index 9b2b299d25..22c3a6e949 100644
--- a/akka-remote/src/test/scala/remote/AkkaRemoteTest.scala
+++ b/akka-remote/src/test/scala/remote/AkkaRemoteTest.scala
@@ -40,20 +40,20 @@ class AkkaRemoteTest extends
remote.asInstanceOf[NettyRemoteSupport].optimizeLocal.set(false) //Can't run the test if we're eliminating all remote calls
}
- override def afterAll {
+ override def afterAll() {
if (!OptimizeLocal)
remote.asInstanceOf[NettyRemoteSupport].optimizeLocal.set(optimizeLocal_?) //Reset optimizelocal after all tests
}
- override def beforeEach {
+ override def beforeEach() {
remote.start(host,port)
super.beforeEach
}
override def afterEach() {
- remote.shutdown
+ remote.shutdown()
Actor.registry.shutdownAll()
- super.afterEach
+ super.afterEach()
}
/* Utilities */
diff --git a/akka-remote/src/test/scala/remote/ClientInitiatedRemoteActorSpec.scala b/akka-remote/src/test/scala/remote/ClientInitiatedRemoteActorSpec.scala
index af5aaffcc3..55f0ac3e3e 100644
--- a/akka-remote/src/test/scala/remote/ClientInitiatedRemoteActorSpec.scala
+++ b/akka-remote/src/test/scala/remote/ClientInitiatedRemoteActorSpec.scala
@@ -101,7 +101,7 @@ class ClientInitiatedRemoteActorSpec extends AkkaRemoteTest {
}
"shouldSendBangBangMessageAndReceiveReplyConcurrently" in {
- val actors = (1 to 10).map(num => { remote.actorOf[RemoteActorSpecActorBidirectional](host,port).start() }).toList
+ val actors = (1 to 5).map(num => { remote.actorOf[RemoteActorSpecActorBidirectional](host,port).start() }).toList
actors.map(_ !!! ("Hello", 10000)) foreach { future =>
"World" must equal (future.await.result.asInstanceOf[Option[String]].get)
}
diff --git a/akka-remote/src/test/scala/remote/ServerInitiatedRemoteActorSample.scala b/akka-remote/src/test/scala/remote/ServerInitiatedRemoteActorSample.scala
index cae866e6e2..0c5a9565a6 100644
--- a/akka-remote/src/test/scala/remote/ServerInitiatedRemoteActorSample.scala
+++ b/akka-remote/src/test/scala/remote/ServerInitiatedRemoteActorSample.scala
@@ -1,8 +1,8 @@
package akka.actor.remote
-import akka.actor.{Actor, ActorRegistry}
-
+import akka.actor.Actor
import Actor._
+import akka.event.EventHandler
/*************************************
Instructions how to run the sample:
@@ -19,14 +19,12 @@ Instructions how to run the sample:
* Then paste in the code below into both shells.
Then run:
-* ServerInitiatedRemoteActorServer.run in one shell
-* ServerInitiatedRemoteActorClient.run in one shell
+* ServerInitiatedRemoteActorServer.run() in one shell
+* ServerInitiatedRemoteActorClient.run() in the other shell
Have fun.
*************************************/
class HelloWorldActor extends Actor {
- self.start()
-
def receive = {
case "Hello" => self.reply("World")
}
@@ -34,16 +32,22 @@ class HelloWorldActor extends Actor {
object ServerInitiatedRemoteActorServer {
- def main(args: Array[String]) = {
- Actor.remote.start("localhost", 2552)
- Actor.remote.register("hello-service", actorOf[HelloWorldActor])
+ def run() {
+ remote.start("localhost", 2552)
+ remote.register("hello-service", actorOf[HelloWorldActor])
}
+
+ def main(args: Array[String]) { run() }
}
object ServerInitiatedRemoteActorClient {
- def main(args: Array[String]) = {
- val actor = Actor.remote.actorFor("hello-service", "localhost", 2552)
+
+ def run() {
+ val actor = remote.actorFor("hello-service", "localhost", 2552)
val result = actor !! "Hello"
+ EventHandler.info("Result from Remote Actor: %s", result)
}
+
+ def main(args: Array[String]) { run() }
}
diff --git a/akka-remote/src/test/scala/remote/ServerInitiatedRemoteSessionActorSpec.scala b/akka-remote/src/test/scala/remote/ServerInitiatedRemoteSessionActorSpec.scala
index c2277200b1..af29bb0bcb 100644
--- a/akka-remote/src/test/scala/remote/ServerInitiatedRemoteSessionActorSpec.scala
+++ b/akka-remote/src/test/scala/remote/ServerInitiatedRemoteSessionActorSpec.scala
@@ -19,8 +19,8 @@ object ServerInitiatedRemoteSessionActorSpec {
class RemoteStatefullSessionActorSpec extends Actor {
- override def preStart = instantiatedSessionActors.add(self)
- override def postStop = instantiatedSessionActors.remove(self)
+ override def preStart() = instantiatedSessionActors.add(self)
+ override def postStop() = instantiatedSessionActors.remove(self)
var user: String = "anonymous"
def receive = {
@@ -48,7 +48,7 @@ class ServerInitiatedRemoteSessionActorSpec extends AkkaRemoteTest {
val result1 = session1 !! GetUser()
result1.as[String] must equal (Some("session[1]"))
- remote.shutdownClientModule
+ remote.shutdownClientModule()
val session2 = remote.actorFor("untyped-session-actor-service", 5000L, host, port)
@@ -66,7 +66,7 @@ class ServerInitiatedRemoteSessionActorSpec extends AkkaRemoteTest {
default1.as[String] must equal (Some("anonymous"))
instantiatedSessionActors must have size (1)
- remote.shutdownClientModule
+ remote.shutdownClientModule()
Thread.sleep(1000)
instantiatedSessionActors must have size (0)
}
diff --git a/akka-remote/src/test/scala/remote/ServerInitiatedRemoteTypedSessionActorSpec.scala b/akka-remote/src/test/scala/remote/ServerInitiatedRemoteTypedSessionActorSpec.scala
index e357127641..e0d1a32ac3 100644
--- a/akka-remote/src/test/scala/remote/ServerInitiatedRemoteTypedSessionActorSpec.scala
+++ b/akka-remote/src/test/scala/remote/ServerInitiatedRemoteTypedSessionActorSpec.scala
@@ -18,8 +18,8 @@ class ServerInitiatedRemoteTypedSessionActorSpec extends AkkaRemoteTest {
}
// make sure the servers shutdown cleanly after the test has finished
- override def afterEach = {
- super.afterEach
+ override def afterEach() {
+ super.afterEach()
clearMessageLogs
}
@@ -32,7 +32,7 @@ class ServerInitiatedRemoteTypedSessionActorSpec extends AkkaRemoteTest {
session1.login("session[1]")
session1.getUser() must equal ("session[1]")
- remote.shutdownClientModule
+ remote.shutdownClientModule()
val session2 = remote.typedActorFor(classOf[RemoteTypedSessionActor], "typed-session-actor-service", 5000L, host, port)
@@ -46,7 +46,7 @@ class ServerInitiatedRemoteTypedSessionActorSpec extends AkkaRemoteTest {
session1.getUser() must equal ("anonymous")
RemoteTypedSessionActorImpl.getInstances() must have size (1)
- remote.shutdownClientModule
+ remote.shutdownClientModule()
Thread.sleep(1000)
RemoteTypedSessionActorImpl.getInstances() must have size (0)
@@ -57,7 +57,7 @@ class ServerInitiatedRemoteTypedSessionActorSpec extends AkkaRemoteTest {
session1.doSomethingFunny()
- remote.shutdownClientModule
+ remote.shutdownClientModule()
Thread.sleep(1000)
RemoteTypedSessionActorImpl.getInstances() must have size (0)
}
diff --git a/akka-remote/src/test/scala/ticket/Ticket434Spec.scala b/akka-remote/src/test/scala/ticket/Ticket434Spec.scala
index 971f200340..55cc4a2659 100644
--- a/akka-remote/src/test/scala/ticket/Ticket434Spec.scala
+++ b/akka-remote/src/test/scala/ticket/Ticket434Spec.scala
@@ -25,7 +25,7 @@ class Ticket434Spec extends AkkaRemoteTest {
latch.await(1, unit) must be (true)
}
- "should be possible to set the acor id and uuuid" in {
+ "should be possible to set the actor id and uuid" in {
val uuid = newUuid
val actorInfo = ActorInfoProtocol.newBuilder
.setUuid(UuidProtocol.newBuilder.setHigh(uuid.getTime).setLow(uuid.getClockSeqAndNode).build)
diff --git a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala
index a19ed26da0..8b0358a4e1 100644
--- a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala
+++ b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala
@@ -6,7 +6,7 @@
import scala.collection.mutable.HashMap
- import akka.actor.{SupervisorFactory, Actor, ActorRef}
+ import akka.actor.{Actor, ActorRef}
import akka.stm._
import akka.config.Supervision.{OneForOneStrategy,Permanent}
import Actor._
@@ -108,7 +108,9 @@
self.reply(ChatLog(messageList))
}
- override def postRestart(reason: Throwable) = chatLog = TransactionalVector()
+ override def postRestart(reason: Throwable) {
+ chatLog = TransactionalVector()
+ }
}
/**
@@ -135,8 +137,9 @@
sessions -= username
}
- protected def shutdownSessions =
+ protected def shutdownSessions() {
sessions.foreach { case (_, session) => session.stop() }
+ }
}
/**
@@ -184,11 +187,11 @@
// abstract methods to be defined somewhere else
protected def chatManagement: Receive
protected def sessionManagement: Receive
- protected def shutdownSessions(): Unit
+ protected def shutdownSessions()
- override def postStop = {
+ override def postStop() {
EventHandler.info(this, "Chat server is shutting down...")
- shutdownSessions
+ shutdownSessions()
self.unlink(storage)
storage.stop()
}
@@ -206,7 +209,7 @@
SessionManagement with
ChatManagement with
MemoryChatStorageFactory {
- override def preStart = {
+ override def preStart() {
remote.start("localhost", 2552);
remote.register("chat:service", self) //Register the actor with the specified service id
}
@@ -217,9 +220,9 @@
*/
object ServerRunner {
- def main(args: Array[String]): Unit = ServerRunner.run
+ def main(args: Array[String]) { ServerRunner.run() }
- def run = {
+ def run() {
actorOf[ChatService].start()
}
}
@@ -229,9 +232,9 @@
*/
object ClientRunner {
- def main(args: Array[String]): Unit = ClientRunner.run
+ def main(args: Array[String]) { ClientRunner.run() }
- def run = {
+ def run() {
val client1 = new ChatClient("jonas")
client1.login
diff --git a/akka-samples/akka-sample-remote/README b/akka-samples/akka-sample-remote/README
index b20d1c7f4e..f19386e1e3 100644
--- a/akka-samples/akka-sample-remote/README
+++ b/akka-samples/akka-sample-remote/README
@@ -1,10 +1,5 @@
---------------------------------------------------------
== Akka Remote Sample Application ==
-
-This sample has two different samples:
- - Server Managed Remote Actors Sample
- - Client Managed Remote Actors Sample
-
---------------------------------------------------------
= Server Managed Remote Actors Sample =
@@ -29,31 +24,4 @@ To run the sample:
Now you could test client reconnect by killing the console running the ServerManagedRemoteActorClient and start it up again. See the client reconnect take place in the REPL shell.
-That’s it. Have fun.
-
----------------------------------------------------------
-= Client Managed Remote Actors Sample =
-
-To run the sample:
-
-1. Fire up two shells. For each of them:
- - Step down into to the root of the Akka distribution.
- - Set 'export AKKA_HOME=.
- - Run 'sbt'
- - Run 'update' followed by 'compile' if you have not done that before.
- - Run 'project akka-sample-remote'
- - Run 'console' to start up a REPL (interpreter).
-2. In the first REPL you get execute:
- - scala> import sample.remote._
- - scala> ClientManagedRemoteActorServer.run
- This starts up the RemoteNode and registers the remote actor
-3. In the second REPL you get execute:
- - scala> import sample.remote._
- - scala> ClientManagedRemoteActorClient.run
-4. See the actor conversation.
-5. Run it again to see full speed after first initialization.
-
-Now you could test client reconnect by killing the console running the ClientManagedRemoteActorClient and start it up again. See the client reconnect take place in the REPL shell.
-
-That’s it. Have fun.
-
+That’s it. Have fun.
\ No newline at end of file
diff --git a/akka-samples/akka-sample-remote/src/main/scala/ClientManagedRemoteActorSample.scala b/akka-samples/akka-sample-remote/src/main/scala/ClientManagedRemoteActorSample.scala
deleted file mode 100644
index 42450b0b39..0000000000
--- a/akka-samples/akka-sample-remote/src/main/scala/ClientManagedRemoteActorSample.scala
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Copyright (C) 2009-2011 Scalable Solutions AB
- */
-
-package sample.remote
-
-import akka.actor.Actor._
-import akka.actor. {ActorRegistry, Actor}
-import Actor.remote
-
-class RemoteHelloWorldActor extends Actor {
- def receive = {
- case "Hello" =>
- self.reply("World")
- }
-}
-
-object ClientManagedRemoteActorServer {
- def run = {
- remote.start("localhost", 2552)
- }
-
- def main(args: Array[String]) = run
-}
-
-object ClientManagedRemoteActorClient {
-
- def run = {
- val actor = remote.actorOf[RemoteHelloWorldActor]("localhost",2552).start()
- val result = actor !! "Hello"
- }
-
- def main(args: Array[String]) = run
-}
-
diff --git a/akka-stm/src/main/scala/akka/transactor/Transactor.scala b/akka-stm/src/main/scala/akka/transactor/Transactor.scala
index 8469aa53dd..57130dec07 100644
--- a/akka-stm/src/main/scala/akka/transactor/Transactor.scala
+++ b/akka-stm/src/main/scala/akka/transactor/Transactor.scala
@@ -82,7 +82,7 @@ case class SendTo(actor: ActorRef, message: Option[Any] = None)
* }}}
*
*
- * To exeucte directly before or after the coordinated transaction, override
+ * To execute directly before or after the coordinated transaction, override
* the `before` and `after` methods. These methods also expect partial functions
* like the receive method. They do not execute within the transaction.
*
diff --git a/akka-testkit/src/main/scala/akka/testkit/CallingThreadDispatcher.scala b/akka-testkit/src/main/scala/akka/testkit/CallingThreadDispatcher.scala
index e6fd8ebbce..319b40b6f4 100644
--- a/akka-testkit/src/main/scala/akka/testkit/CallingThreadDispatcher.scala
+++ b/akka-testkit/src/main/scala/akka/testkit/CallingThreadDispatcher.scala
@@ -28,6 +28,11 @@ import scala.annotation.tailrec
*/
object CallingThreadDispatcher {
+
+ lazy val global = new CallingThreadDispatcher
+
+ // PRIVATE DATA
+
private var queues = Map[CallingThreadMailbox, Set[WeakReference[NestingQueue]]]()
// we have to forget about long-gone threads sometime
@@ -35,7 +40,7 @@ object CallingThreadDispatcher {
queues = queues mapValues (_ filter (_.get ne null)) filter (!_._2.isEmpty)
}
- def registerQueue(mbox : CallingThreadMailbox, q : NestingQueue) : Unit = synchronized {
+ private[akka] def registerQueue(mbox : CallingThreadMailbox, q : NestingQueue) : Unit = synchronized {
if (queues contains mbox) {
val newSet = queues(mbox) + new WeakReference(q)
queues += mbox -> newSet
@@ -50,7 +55,7 @@ object CallingThreadDispatcher {
* given mailbox. When this method returns, the queue will be entered
* (active).
*/
- def gatherFromAllInactiveQueues(mbox : CallingThreadMailbox, own : NestingQueue) : Unit = synchronized {
+ private[akka] def gatherFromAllInactiveQueues(mbox : CallingThreadMailbox, own : NestingQueue) : Unit = synchronized {
if (!own.isActive) own.enter
if (queues contains mbox) {
for {
@@ -103,9 +108,9 @@ class CallingThreadDispatcher(val warnings: Boolean = true) extends MessageDispa
private def getMailbox(actor: ActorRef) = actor.mailbox.asInstanceOf[CallingThreadMailbox]
- private[akka] override def start {}
+ private[akka] override def start() {}
- private[akka] override def shutdown {}
+ private[akka] override def shutdown() {}
private[akka] override def timeoutMs = 100L
@@ -151,7 +156,7 @@ class CallingThreadDispatcher(val warnings: Boolean = true) extends MessageDispa
if (execute) runQueue(mbox, queue)
}
- private[akka] override def executeFuture(invocation: FutureInvocation) { invocation.run }
+ private[akka] override def executeFuture(invocation: FutureInvocation[_]) { invocation.run }
/*
* This method must be called with this thread's queue, which must already
diff --git a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala
new file mode 100644
index 0000000000..53ceed69eb
--- /dev/null
+++ b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala
@@ -0,0 +1,85 @@
+package akka.testkit
+
+import akka.actor._
+import akka.util.ReflectiveAccess
+import akka.event.EventHandler
+
+/**
+ * This special ActorRef is exclusively for use during unit testing in a single-threaded environment. Therefore, it
+ * overrides the dispatcher to CallingThreadDispatcher and sets the receiveTimeout to None. Otherwise,
+ * it acts just like a normal ActorRef. You may retrieve a reference to the underlying actor to test internal logic.
+ *
+ *
+ * @author Roland Kuhn
+ * @since 1.1
+ */
+class TestActorRef[T <: Actor](factory: () => T) extends LocalActorRef(factory, None) {
+
+ dispatcher = CallingThreadDispatcher.global
+ receiveTimeout = None
+
+ /**
+ * Query actor's current receive behavior.
+ */
+ override def isDefinedAt(o : Any) = actor.isDefinedAt(o)
+
+ /**
+ * Directly inject messages into actor receive behavior. Any exceptions
+ * thrown will be available to you, while still being able to use
+ * become/unbecome and their message counterparts.
+ */
+ def apply(o : Any) { actor(o) }
+
+ /**
+ * Retrieve reference to the underlying actor, where the static type matches the factory used inside the
+ * constructor. Beware that this reference is discarded by the ActorRef upon restarting the actor (should this
+ * reference be linked to a supervisor). The old Actor may of course still be used in post-mortem assertions.
+ */
+ def underlyingActor : T = actor.asInstanceOf[T]
+
+ /**
+ * Override to return the more specific static type.
+ */
+ override def start() = {
+ super.start()
+ this
+ }
+
+ override def toString = "TestActor[" + id + ":" + uuid + "]"
+
+ override def equals(other : Any) =
+ other.isInstanceOf[TestActorRef[_]] &&
+ other.asInstanceOf[TestActorRef[_]].uuid == uuid
+
+ /**
+ * Override to check whether the new supervisor is running on the CallingThreadDispatcher,
+ * as it should be. This can of course be tricked by linking before setting the dispatcher before starting the
+ * supervisor, but then you just asked for trouble.
+ */
+ override def supervisor_=(a : Option[ActorRef]) {
+ for (ref <- a) {
+ if (!ref.dispatcher.isInstanceOf[CallingThreadDispatcher])
+ EventHandler.warning(this, "supervisor "+ref+" does not use CallingThreadDispatcher")
+ }
+ super.supervisor_=(a)
+ }
+
+}
+
+object TestActorRef {
+
+ def apply[T <: Actor](factory: => T) = new TestActorRef(() => factory)
+
+ def apply[T <: Actor : Manifest] : TestActorRef[T] = new TestActorRef[T] ({ () =>
+ import ReflectiveAccess.{ createInstance, noParams, noArgs }
+ createInstance[T](manifest[T].erasure, noParams, noArgs) match {
+ case r: Right[_, T] => r.b
+ case l: Left[Exception, _] => throw new ActorInitializationException(
+ "Could not instantiate Actor" +
+ "\nMake sure Actor is NOT defined inside a class/trait," +
+ "\nif so put it outside the class/trait, f.e. in a companion object," +
+ "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.", l.a)
+ }
+ })
+
+}
diff --git a/akka-testkit/src/main/scala/akka/testkit/TestKit.scala b/akka-testkit/src/main/scala/akka/testkit/TestKit.scala
index 397635c628..fdad53c4ff 100644
--- a/akka-testkit/src/main/scala/akka/testkit/TestKit.scala
+++ b/akka-testkit/src/main/scala/akka/testkit/TestKit.scala
@@ -20,6 +20,8 @@ class TestActor(queue : BlockingDeque[AnyRef]) extends Actor with FSM[Int, TestA
import FSM._
import TestActor._
+ self.dispatcher = CallingThreadDispatcher.global
+
startWith(0, None)
when(0, stateTimeout = 5 seconds) {
case Ev(SetTimeout(d)) =>
@@ -157,7 +159,7 @@ trait TestKit {
val prev_end = end
end = start + max_diff
- val ret = f
+ val ret = try f finally end = prev_end
val diff = now - start
assert (min <= diff, "block took "+format(min.unit, diff)+", should at least have been "+min)
@@ -170,7 +172,6 @@ trait TestKit {
lastSoftTimeout -= 5.millis
}
- end = prev_end
ret
}
diff --git a/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala b/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala
new file mode 100644
index 0000000000..fa203f2a1c
--- /dev/null
+++ b/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala
@@ -0,0 +1,258 @@
+package akka.testkit
+
+import org.scalatest.matchers.MustMatchers
+import org.scalatest.{BeforeAndAfterEach, WordSpec}
+import akka.actor._
+import akka.config.Supervision.OneForOneStrategy
+import akka.event.EventHandler
+import akka.dispatch.Future
+
+/**
+ * Test whether TestActorRef behaves as an ActorRef should, besides its own spec.
+ *
+ * @author Roland Kuhn
+ */
+
+object TestActorRefSpec {
+
+ var counter = 4
+ val thread = Thread.currentThread
+ var otherthread : Thread = null
+
+ trait TActor extends Actor {
+ def receive = new Receive {
+ val recv = receiveT
+ def isDefinedAt(o : Any) = recv.isDefinedAt(o)
+ def apply(o : Any) {
+ if (Thread.currentThread ne thread)
+ otherthread = Thread.currentThread
+ recv(o)
+ }
+ }
+ def receiveT : Receive
+ }
+
+ class ReplyActor extends TActor {
+ var replyTo: Channel[Any] = null
+
+ def receiveT = {
+ case "complexRequest" => {
+ replyTo = self.channel
+ val worker = TestActorRef[WorkerActor].start()
+ worker ! "work"
+ }
+ case "complexRequest2" =>
+ val worker = TestActorRef[WorkerActor].start()
+ worker ! self.channel
+ case "workDone" => replyTo ! "complexReply"
+ case "simpleRequest" => self.reply("simpleReply")
+ }
+ }
+
+ class WorkerActor() extends TActor {
+ def receiveT = {
+ case "work" => {
+ self.reply("workDone")
+ self.stop()
+ }
+ case replyTo: Channel[Any] => {
+ replyTo ! "complexReply"
+ }
+ }
+ }
+
+ class SenderActor(replyActor: ActorRef) extends TActor {
+
+ def receiveT = {
+ case "complex" => replyActor ! "complexRequest"
+ case "complex2" => replyActor ! "complexRequest2"
+ case "simple" => replyActor ! "simpleRequest"
+ case "complexReply" => {
+ counter -= 1
+ }
+ case "simpleReply" => {
+ counter -= 1
+ }
+ }
+ }
+
+ class Logger extends Actor {
+ import EventHandler._
+ var count = 0
+ var msg : String = _
+ def receive = {
+ case Warning(_, m : String) => count += 1; msg = m
+ }
+ }
+
+}
+
+class TestActorRefSpec extends WordSpec with MustMatchers with BeforeAndAfterEach {
+
+ import TestActorRefSpec._
+
+ override def beforeEach {
+ otherthread = null
+ }
+
+ private def assertThread {
+ otherthread must (be (null) or equal (thread))
+ }
+
+ "A TestActorRef must be an ActorRef, hence it" must {
+
+ "support nested Actor creation" when {
+
+ "used with TestActorRef" in {
+ val a = TestActorRef(new Actor {
+ val nested = TestActorRef(new Actor { def receive = { case _ => } }).start()
+ def receive = { case _ => self reply nested }
+ }).start()
+ a must not be (null)
+ val nested = (a !! "any").get.asInstanceOf[ActorRef]
+ nested must not be (null)
+ a must not be theSameInstanceAs (nested)
+ }
+
+ "used with ActorRef" in {
+ val a = TestActorRef(new Actor {
+ val nested = Actor.actorOf(new Actor { def receive = { case _ => } }).start()
+ def receive = { case _ => self reply nested }
+ }).start()
+ a must not be (null)
+ val nested = (a !! "any").get.asInstanceOf[ActorRef]
+ nested must not be (null)
+ a must not be theSameInstanceAs (nested)
+ }
+
+ }
+
+ "support reply via channel" in {
+ val serverRef = TestActorRef[ReplyActor].start()
+ val clientRef = TestActorRef(new SenderActor(serverRef)).start()
+
+ counter = 4
+
+ clientRef ! "complex"
+ clientRef ! "simple"
+ clientRef ! "simple"
+ clientRef ! "simple"
+
+ counter must be (0)
+
+ counter = 4
+
+ clientRef ! "complex2"
+ clientRef ! "simple"
+ clientRef ! "simple"
+ clientRef ! "simple"
+
+ counter must be (0)
+
+ assertThread
+ }
+
+ "stop when sent a poison pill" in {
+ val a = TestActorRef[WorkerActor].start()
+ intercept[ActorKilledException] {
+ a !! PoisonPill
+ }
+ a must not be ('running)
+ a must be ('shutdown)
+ assertThread
+ }
+
+ "restart when Kill:ed" in {
+ counter = 2
+
+ val boss = TestActorRef(new TActor {
+ self.faultHandler = OneForOneStrategy(List(classOf[Throwable]), Some(2), Some(1000))
+ val ref = TestActorRef(new TActor {
+ def receiveT = { case _ => }
+ override def preRestart(reason: Throwable) { counter -= 1 }
+ override def postRestart(reason: Throwable) { counter -= 1 }
+ }).start()
+ self.dispatcher = CallingThreadDispatcher.global
+ self link ref
+ def receiveT = { case "sendKill" => ref ! Kill }
+ }).start()
+
+ val l = stopLog()
+ boss ! "sendKill"
+ startLog(l)
+
+ counter must be (0)
+ assertThread
+ }
+
+ "support futures" in {
+ val a = TestActorRef[WorkerActor].start()
+ val f : Future[String] = a !!! "work"
+ f must be ('completed)
+ f.get must equal ("workDone")
+ }
+
+ }
+
+ "A TestActorRef" must {
+
+ "allow access to internals" in {
+ val ref = TestActorRef(new TActor {
+ var s : String = _
+ def receiveT = {
+ case x : String => s = x
+ }
+ }).start()
+ ref ! "hallo"
+ val actor = ref.underlyingActor
+ actor.s must equal ("hallo")
+ }
+
+ "set receiveTimeout to None" in {
+ val a = TestActorRef[WorkerActor]
+ a.receiveTimeout must be (None)
+ }
+
+ "set CallingThreadDispatcher" in {
+ val a = TestActorRef[WorkerActor]
+ a.dispatcher.getClass must be (classOf[CallingThreadDispatcher])
+ }
+
+ "warn about scheduled supervisor" in {
+ val boss = Actor.actorOf(new Actor { def receive = { case _ => } }).start()
+ val ref = TestActorRef[WorkerActor].start()
+
+ val log = TestActorRef[Logger]
+ EventHandler.addListener(log)
+ boss link ref
+ val la = log.underlyingActor
+ la.count must be (1)
+ la.msg must (include ("supervisor") and include ("CallingThreadDispatcher"))
+ EventHandler.removeListener(log)
+ }
+
+ "proxy isDefinedAt/apply for the underlying actor" in {
+ val ref = TestActorRef[WorkerActor].start()
+ ref.isDefinedAt("work") must be (true)
+ ref.isDefinedAt("sleep") must be (false)
+ intercept[IllegalActorStateException] { ref("work") }
+ val ch = Future.channel()
+ ref ! ch
+ val f = ch.future
+ f must be ('completed)
+ f.get must be ("complexReply")
+ }
+
+ }
+
+ private def stopLog() = {
+ val l = Actor.registry.actorsFor[EventHandler.DefaultListener]
+ l foreach (EventHandler.removeListener(_))
+ l
+ }
+
+ private def startLog(l : Array[ActorRef]) {
+ l foreach {a => EventHandler.addListener(Actor.actorOf[EventHandler.DefaultListener])}
+ }
+
+}
diff --git a/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java b/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java
index 8c0085fb97..034dec5178 100644
--- a/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java
+++ b/akka-tutorials/akka-tutorial-first/src/main/java/akka/tutorial/first/java/Pi.java
@@ -87,7 +87,7 @@ public class Pi {
private double calculatePiFor(int start, int nrOfElements) {
double acc = 0.0;
for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
- acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1);
+ acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1);
}
return acc;
}
diff --git a/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala b/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala
index c16c53f995..41f562791a 100644
--- a/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala
+++ b/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala
@@ -59,7 +59,7 @@ object Pi extends App {
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
var acc = 0.0
for (i <- start until (start + nrOfElements))
- acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1)
+ acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)
acc
}
@@ -104,11 +104,11 @@ object Pi extends App {
if (nrOfResults == nrOfMessages) self.stop()
}
- override def preStart {
+ override def preStart() {
start = System.currentTimeMillis
}
- override def postStop {
+ override def postStop() {
// tell the world that the calculation is complete
println(
"\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
diff --git a/akka-tutorials/akka-tutorial-second/src/main/scala/Pi.scala b/akka-tutorials/akka-tutorial-second/src/main/scala/Pi.scala
index e7e10f56ef..35d29f8f6c 100644
--- a/akka-tutorials/akka-tutorial-second/src/main/scala/Pi.scala
+++ b/akka-tutorials/akka-tutorial-second/src/main/scala/Pi.scala
@@ -111,7 +111,7 @@ object Pi extends App {
def receive = scatter
// when we are stopped, stop our team of workers and our router
- override def postStop {
+ override def postStop() {
// send a PoisonPill to all workers telling them to shut down themselves
router ! Broadcast(PoisonPill)
// send a PoisonPill to the router, telling him to shut himself down
diff --git a/akka-typed-actor/src/main/scala/akka/actor/TypedActor.scala b/akka-typed-actor/src/main/scala/akka/actor/TypedActor.scala
index 7103c3fd5b..591613a203 100644
--- a/akka-typed-actor/src/main/scala/akka/actor/TypedActor.scala
+++ b/akka-typed-actor/src/main/scala/akka/actor/TypedActor.scala
@@ -83,11 +83,11 @@ import scala.reflect.BeanProperty
*
* def square(x: Int): Future[Integer] = future(x * x)
*
- * override def preStart = {
+ * override def preStart() = {
* ... // optional initialization on start
* }
*
- * override def postStop = {
+ * override def postStop() = {
* ... // optional cleanup on stop
* }
*
@@ -160,14 +160,14 @@ abstract class TypedActor extends Actor with Proxyable {
*
* Is called when an Actor is started by invoking 'actor.start()'.
*/
- override def preStart {}
+ override def preStart() {}
/**
* User overridable callback.
*
* Is called when 'actor.stop()' is invoked.
*/
- override def postStop {}
+ override def postStop() {}
/**
* User overridable callback.
diff --git a/akka-typed-actor/src/main/scala/akka/config/TypedActorGuiceConfigurator.scala b/akka-typed-actor/src/main/scala/akka/config/TypedActorGuiceConfigurator.scala
index ae19601351..98ce6d8b20 100644
--- a/akka-typed-actor/src/main/scala/akka/config/TypedActorGuiceConfigurator.scala
+++ b/akka-typed-actor/src/main/scala/akka/config/TypedActorGuiceConfigurator.scala
@@ -173,7 +173,7 @@ private[akka] class TypedActorGuiceConfigurator extends TypedActorConfiguratorBa
}
def stop = synchronized {
- if (supervisor.isDefined) supervisor.get.shutdown
+ if (supervisor.isDefined) supervisor.get.shutdown()
}
}
diff --git a/akka-typed-actor/src/main/scala/akka/transactor/Coordination.scala b/akka-typed-actor/src/main/scala/akka/transactor/Coordination.scala
index 33a74fea79..1f72176eed 100644
--- a/akka-typed-actor/src/main/scala/akka/transactor/Coordination.scala
+++ b/akka-typed-actor/src/main/scala/akka/transactor/Coordination.scala
@@ -9,7 +9,7 @@ import akka.stm.Atomic
import scala.util.DynamicVariable
-class CoordinateException private[akka](message: String) extends AkkaException(message)
+class CoordinateException private[akka](message: String, cause: Throwable = null) extends AkkaException(message, cause)
/**
* Coordinating transactions between typed actors.
diff --git a/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorRegistrySpec.scala b/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorRegistrySpec.scala
index a83dccc18d..fd99974775 100644
--- a/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorRegistrySpec.scala
+++ b/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorRegistrySpec.scala
@@ -16,7 +16,7 @@ class TypedActorRegistrySpec extends WordSpec with MustMatchers {
"Typed Actor" should {
- "be able to be retreived from the registry by class" in {
+ "be able to be retrieved from the registry by class" in {
Actor.registry.shutdownAll()
val my = TypedActor.newInstance[My](classOf[My], classOf[MyImpl], 3000)
val actors = Actor.registry.typedActorsFor(classOf[My])
@@ -24,7 +24,7 @@ class TypedActorRegistrySpec extends WordSpec with MustMatchers {
Actor.registry.shutdownAll()
}
- "be able to be retreived from the registry by manifest" in {
+ "be able to be retrieved from the registry by manifest" in {
Actor.registry.shutdownAll()
val my = TypedActor.newInstance[My](classOf[My], classOf[MyImpl], 3000)
val option = Actor.registry.typedActorFor[My]
@@ -33,7 +33,7 @@ class TypedActorRegistrySpec extends WordSpec with MustMatchers {
Actor.registry.shutdownAll()
}
- "be able to be retreived from the registry by class two times" in {
+ "be able to be retrieved from the registry by class two times" in {
Actor.registry.shutdownAll()
val my = TypedActor.newInstance[My](classOf[My], classOf[MyImpl], 3000)
val actors1 = Actor.registry.typedActorsFor(classOf[My])
@@ -43,7 +43,7 @@ class TypedActorRegistrySpec extends WordSpec with MustMatchers {
Actor.registry.shutdownAll()
}
- "be able to be retreived from the registry by manifest two times" in {
+ "be able to be retrieved from the registry by manifest two times" in {
Actor.registry.shutdownAll()
val my = TypedActor.newInstance[My](classOf[My], classOf[MyImpl], 3000)
val option1 = Actor.registry.typedActorFor[My]
@@ -55,7 +55,7 @@ class TypedActorRegistrySpec extends WordSpec with MustMatchers {
Actor.registry.shutdownAll()
}
- "be able to be retreived from the registry by manifest two times (even when created in supervisor)" in {
+ "be able to be retrieved from the registry by manifest two times (even when created in supervisor)" in {
Actor.registry.shutdownAll()
val manager = new TypedActorConfigurator
manager.configure(
diff --git a/config/akka-reference.conf b/config/akka-reference.conf
index df2c2c3e0d..9a647c6ad5 100644
--- a/config/akka-reference.conf
+++ b/config/akka-reference.conf
@@ -85,7 +85,7 @@ akka {
port = 9998
#If you are using akka.http.AkkaRestServlet
- filters = ["se.scalablesolutions.akka.security.AkkaSecurityFilterFactory"] # List with all jersey filters to use
+ filters = ["akka.security.AkkaSecurityFilterFactory"] # List with all jersey filters to use
# resource-packages = ["sample.rest.scala",
# "sample.rest.java",
# "sample.security"] # List with all resource packages for your Jersey services
@@ -123,7 +123,7 @@ akka {
remote {
- # secure-cookie = "050E0A0D0D06010A00000900040D060F0C09060B" # generate your own with '$AKKA_HOME/scripts/generate_secure_cookie.sh' or using 'Crypt.generateSecureCookie'
+ # secure-cookie = "050E0A0D0D06010A00000900040D060F0C09060B" # generate your own with '$AKKA_HOME/scripts/generate_config_with_secure_cookie.sh' or using 'Crypt.generateSecureCookie'
secure-cookie = ""
compression-scheme = "zlib" # Options: "zlib" (lzf to come), leave out for no compression
diff --git a/project/build/AkkaProject.scala b/project/build/AkkaProject.scala
index 597d01f490..4336f5a661 100644
--- a/project/build/AkkaProject.scala
+++ b/project/build/AkkaProject.scala
@@ -10,7 +10,7 @@ import sbt._
import sbt.CompileOrder._
import spde._
-class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with AutoCompilerPlugins {
+class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) {
// -------------------------------------------------------------------------------------------------------------------
// Compile settings
@@ -27,42 +27,6 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
override def compileOptions = super.compileOptions ++ scalaCompileSettings.map(CompileOption)
override def javaCompileOptions = super.javaCompileOptions ++ javaCompileSettings.map(JavaCompileOption)
- // -------------------------------------------------------------------------------------------------------------------
- // Deploy/dist settings
- // -------------------------------------------------------------------------------------------------------------------
- val distName = "%s-%s".format(name, version)
- val distArchiveName = distName + ".zip"
- val deployPath = info.projectPath / "deploy"
- val distPath = info.projectPath / "dist"
- val distArchive = (distPath ##) / distArchiveName
-
- lazy override val `package` = task { None }
-
- //The distribution task, packages Akka into a zipfile and places it into the projectPath/dist directory
- lazy val dist = task {
-
- def transferFile(from: Path, to: Path) =
- if ( from.asFile.renameTo(to.asFile) ) None
- else Some("Couldn't transfer %s to %s".format(from,to))
-
- //Creates a temporary directory where we can assemble the distribution
- val genDistDir = Path.fromFile({
- val d = File.createTempFile("akka","dist")
- d.delete //delete the file
- d.mkdir //Recreate it as a dir
- d
- }).## //## is needed to make sure that the zipped archive has the correct root folder
-
- //Temporary directory to hold the dist currently being generated
- val currentDist = genDistDir / distName
-
- FileUtilities.copy(allArtifacts.get, currentDist, log).left.toOption orElse //Copy all needed artifacts into the root archive
- FileUtilities.zip(List(currentDist), distArchiveName, true, log) orElse //Compress the root archive into a zipfile
- transferFile(info.projectPath / distArchiveName, distArchive) orElse //Move the archive into the dist folder
- FileUtilities.clean(genDistDir,log) //Cleanup the generated jars
-
- } dependsOn (`package`) describedAs("Zips up the distribution.")
-
// -------------------------------------------------------------------------------------------------------------------
// All repositories *must* go here! See ModuleConigurations below.
// -------------------------------------------------------------------------------------------------------------------
@@ -114,7 +78,7 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
lazy val JERSEY_VERSION = "1.3"
lazy val MULTIVERSE_VERSION = "0.6.2"
lazy val SCALATEST_VERSION = "1.4-SNAPSHOT"
- lazy val JETTY_VERSION = "7.2.2.v20101205"
+ lazy val JETTY_VERSION = "7.4.0.v20110414"
lazy val JAVAX_SERVLET_VERSION = "3.0"
lazy val SLF4J_VERSION = "1.6.0"
@@ -197,14 +161,6 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
override def disableCrossPaths = true
- override def packageOptions =
- manifestClassPath.map(cp => ManifestAttributes(
- (Attributes.Name.CLASS_PATH, cp),
- (IMPLEMENTATION_TITLE, "Akka"),
- (IMPLEMENTATION_URL, "http://akka.io"),
- (IMPLEMENTATION_VENDOR, "Scalable Solutions AB")
- )).toList
-
//Exclude slf4j1.5.11 from the classpath, it's conflicting...
override def fullClasspath(config: Configuration): PathFinder = {
super.fullClasspath(config) ---
@@ -250,7 +206,7 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
override def deliverProjectDependencies = super.deliverProjectDependencies.toList - akka_samples.projectID - akka_tutorials.projectID
- // ------------------------------------------------------------
+ // ------------------------------------------------------------
// Build release
// ------------------------------------------------------------
@@ -265,15 +221,13 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
publishTask(publishIvyModule, releaseConfiguration) dependsOn (deliver, publishLocal, makePom)
}
- lazy val buildRelease = task {
- FileUtilities.copy(Seq(distArchive), localReleaseDownloads, log).left.toOption
- } dependsOn (publishRelease, dist)
+ lazy val buildRelease = task { None } dependsOn publishRelease
// -------------------------------------------------------------------------------------------------------------------
// akka-actor subproject
// -------------------------------------------------------------------------------------------------------------------
- class AkkaActorProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath) with OsgiProject with AutoCompilerPlugins {
+ class AkkaActorProject(info: ProjectInfo) extends AkkaDefaultProject(info) with OsgiProject with AutoCompilerPlugins {
override def bndExportPackage = super.bndExportPackage ++ Seq("com.eaio.*;version=3.2")
val cont = compilerPlugin("org.scala-lang.plugins" % "continuations" % "2.9.0.RC1")
override def compileOptions = super.compileOptions ++ compileOptions("-P:continuations:enable")
@@ -283,7 +237,7 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
// akka-stm subproject
// -------------------------------------------------------------------------------------------------------------------
- class AkkaStmProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath) {
+ class AkkaStmProject(info: ProjectInfo) extends AkkaDefaultProject(info) {
val multiverse = Dependencies.multiverse
// testing
@@ -295,7 +249,7 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
// akka-typed-actor subproject
// -------------------------------------------------------------------------------------------------------------------
- class AkkaTypedActorProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath) {
+ class AkkaTypedActorProject(info: ProjectInfo) extends AkkaDefaultProject(info) {
val aopalliance = Dependencies.aopalliance
val aspectwerkz = Dependencies.aspectwerkz
val guicey = Dependencies.guicey
@@ -312,7 +266,7 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
// akka-remote subproject
// -------------------------------------------------------------------------------------------------------------------
- class AkkaRemoteProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath) {
+ class AkkaRemoteProject(info: ProjectInfo) extends AkkaDefaultProject(info) {
val commons_codec = Dependencies.commons_codec
val commons_io = Dependencies.commons_io
val guicey = Dependencies.guicey
@@ -339,7 +293,7 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
// akka-http subproject
// -------------------------------------------------------------------------------------------------------------------
- class AkkaHttpProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath) {
+ class AkkaHttpProject(info: ProjectInfo) extends AkkaDefaultProject(info) {
val jsr250 = Dependencies.jsr250
val javax_servlet30 = Dependencies.javax_servlet_30
val jetty = Dependencies.jetty
@@ -373,13 +327,13 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
}
}
- class AkkaSampleRemoteProject(info: ProjectInfo) extends AkkaDefaultProject(info, deployPath)
+ class AkkaSampleRemoteProject(info: ProjectInfo) extends AkkaDefaultProject(info)
- class AkkaSampleChatProject(info: ProjectInfo) extends AkkaDefaultProject(info, deployPath)
+ class AkkaSampleChatProject(info: ProjectInfo) extends AkkaDefaultProject(info)
- class AkkaSampleFSMProject(info: ProjectInfo) extends AkkaDefaultProject(info, deployPath)
+ class AkkaSampleFSMProject(info: ProjectInfo) extends AkkaDefaultProject(info)
- class AkkaSampleOsgiProject(info: ProjectInfo) extends AkkaDefaultProject(info, deployPath) with BNDPlugin {
+ class AkkaSampleOsgiProject(info: ProjectInfo) extends AkkaDefaultProject(info) with BNDPlugin {
val osgiCore = Dependencies.osgi_core
override protected def bndPrivatePackage = List("sample.osgi.*")
override protected def bndBundleActivator = Some("sample.osgi.Activator")
@@ -409,9 +363,9 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
// Tutorials
// -------------------------------------------------------------------------------------------------------------------
- class AkkaTutorialFirstProject(info: ProjectInfo) extends AkkaDefaultProject(info, deployPath)
+ class AkkaTutorialFirstProject(info: ProjectInfo) extends AkkaDefaultProject(info)
- class AkkaTutorialSecondProject(info: ProjectInfo) extends AkkaDefaultProject(info, deployPath)
+ class AkkaTutorialSecondProject(info: ProjectInfo) extends AkkaDefaultProject(info)
class AkkaTutorialsParentProject(info: ProjectInfo) extends ParentProject(info) {
override def disableCrossPaths = true
@@ -432,59 +386,35 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
// akka-testkit subproject
// -------------------------------------------------------------------------------------------------------------------
- class AkkaTestkitProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath)
+ class AkkaTestkitProject(info: ProjectInfo) extends AkkaDefaultProject(info) {
+ val scalatest = Dependencies.scalatest
+ }
// -------------------------------------------------------------------------------------------------------------------
// akka-actor-tests subproject
// -------------------------------------------------------------------------------------------------------------------
- class AkkaActorTestsProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath) with AutoCompilerPlugins {
+ class AkkaActorTestsProject(info: ProjectInfo) extends AkkaDefaultProject(info) with AutoCompilerPlugins {
// testing
val junit = Dependencies.junit
val scalatest = Dependencies.scalatest
val multiverse_test = Dependencies.multiverse_test // StandardLatch
override def compileOptions = super.compileOptions ++ compileOptions("-P:continuations:enable")
}
-
+
// -------------------------------------------------------------------------------------------------------------------
// akka-slf4j subproject
// -------------------------------------------------------------------------------------------------------------------
- class AkkaSlf4jProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath) {
+ class AkkaSlf4jProject(info: ProjectInfo) extends AkkaDefaultProject(info) {
val slf4j = Dependencies.slf4j
}
// -------------------------------------------------------------------------------------------------------------------
- // Helpers
+ // Default project
// -------------------------------------------------------------------------------------------------------------------
- def removeDupEntries(paths: PathFinder) = Path.lazyPathFinder {
- val mapped = paths.get map { p => (p.relativePath, p) }
- (Map() ++ mapped).values.toList
- }
-
- def allArtifacts = {
- Path.fromFile(buildScalaInstance.libraryJar) +++
- (removeDupEntries(runClasspath filter ClasspathUtilities.isArchive) +++
- ((outputPath ##) / defaultJarName) +++
- mainResources +++
- mainDependencies.scalaJars +++
- descendents(info.projectPath / "scripts", "run_akka.sh") +++
- descendents(info.projectPath / "scripts", "akka-init-script.sh") +++
- descendents(info.projectPath / "dist", "*.jar") +++
- descendents(info.projectPath / "deploy", "*.jar") +++
- descendents(path("lib") ##, "*.jar") +++
- descendents(configurationPath(Configurations.Compile) ##, "*.jar"))
- .filter(jar => // remove redundant libs
- !jar.toString.endsWith("stax-api-1.0.1.jar") ||
- !jar.toString.endsWith("scala-library-2.7.7.jar")
- )
- }
-
- def akkaArtifacts = descendents(info.projectPath / "dist", "*-" + version + ".jar")
-
- // ------------------------------------------------------------
- class AkkaDefaultProject(info: ProjectInfo, val deployPath: Path) extends DefaultProject(info) with DeployProject with McPom {
+ class AkkaDefaultProject(info: ProjectInfo) extends DefaultProject(info) with McPom {
override def disableCrossPaths = true
@@ -516,27 +446,6 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) with Aut
}
}
-trait DeployProject { self: BasicScalaProject =>
- // defines where the deployTask copies jars to
- def deployPath: Path
-
- lazy val dist = deployTask(jarPath, packageDocsJar, packageSrcJar, deployPath, true, true, true) dependsOn(
- `package`, packageDocs, packageSrc) describedAs("Deploying")
-
- def deployTask(jar: Path, docs: Path, src: Path, toDir: Path,
- genJar: Boolean, genDocs: Boolean, genSource: Boolean) = task {
- def gen(jar: Path, toDir: Path, flag: Boolean, msg: String): Option[String] =
- if (flag) {
- log.info(msg + " " + jar)
- FileUtilities.copyFile(jar, toDir / jar.name, log)
- } else None
-
- gen(jar, toDir, genJar, "Deploying bits") orElse
- gen(docs, toDir, genDocs, "Deploying docs") orElse
- gen(src, toDir, genSource, "Deploying sources")
- }
-}
-
trait OsgiProject extends BNDPlugin { self: DefaultProject =>
override def bndExportPackage = Seq("akka.*;version=%s".format(projectVersion.value))
}