From 15748e5c426321fb0b07feee32630e32d95d3c4f Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Mon, 28 Nov 2011 16:05:22 +0100 Subject: [PATCH 01/23] Execute scheduled tasks in system default dispatcher. See #1380 --- .../src/main/scala/akka/actor/ActorRefProvider.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index 764838cdb8..144bb5dc9f 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -429,8 +429,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) private def createSingleTask(runnable: Runnable): TimerTask = new TimerTask() { def run(timeout: org.jboss.netty.akka.util.Timeout) { - // FIXME: consider executing runnable inside main dispatcher to prevent blocking of scheduler - runnable.run() + system.dispatcher.dispatchTask(() ⇒ runnable.run()) } } @@ -444,7 +443,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) private def createSingleTask(f: () ⇒ Unit): TimerTask = new TimerTask { def run(timeout: org.jboss.netty.akka.util.Timeout) { - f() + system.dispatcher.dispatchTask(f) } } @@ -465,7 +464,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) private def createContinuousTask(f: () ⇒ Unit, delay: Duration): TimerTask = { new TimerTask { def run(timeout: org.jboss.netty.akka.util.Timeout) { - f() + system.dispatcher.dispatchTask(f) timeout.getTimer.newTimeout(this, delay) } } From abf4b52f3e065302b1d1343e9badb698708e75d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bone=CC=81r?= Date: Mon, 28 Nov 2011 17:07:31 +0100 Subject: [PATCH 02/23] Added *.vim to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 857686b6aa..91eba2fc6b 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.vim *~ *# src_managed From 4d920916bbfdb9d78b15a8d7930bcdbab837afec Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Tue, 29 Nov 2011 08:07:41 +0100 Subject: [PATCH 03/23] Added dispatcher to constructor of DefaultDispatcher. See #1380 * There is circular initialization dependencies between DefaultScheduler and Dispatchers, therefore I used (lazy) by-name parameter. --- .../scala/akka/actor/ActorRefProvider.scala | 15 +++++++---- .../main/scala/akka/actor/ActorSystem.scala | 27 +++++++++++++++++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index 144bb5dc9f..f33dd3f0c5 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -409,7 +409,12 @@ class LocalDeathWatch extends DeathWatch with ActorClassification { } } -class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) extends Scheduler { +/** + * Scheduled tasks (Runnable and functions) are executed with the supplied dispatcher. + * Note that dispatcher is by-name parameter, because dispatcher might not be initialized + * when the scheduler is created. + */ +class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, log: LoggingAdapter, dispatcher: ⇒ MessageDispatcher) extends Scheduler { def schedule(receiver: ActorRef, message: Any, initialDelay: Duration, delay: Duration): Cancellable = new DefaultCancellable(hashedWheelTimer.newTimeout(createContinuousTask(receiver, message, delay), initialDelay)) @@ -429,7 +434,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) private def createSingleTask(runnable: Runnable): TimerTask = new TimerTask() { def run(timeout: org.jboss.netty.akka.util.Timeout) { - system.dispatcher.dispatchTask(() ⇒ runnable.run()) + dispatcher.dispatchTask(() ⇒ runnable.run()) } } @@ -443,7 +448,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) private def createSingleTask(f: () ⇒ Unit): TimerTask = new TimerTask { def run(timeout: org.jboss.netty.akka.util.Timeout) { - system.dispatcher.dispatchTask(f) + dispatcher.dispatchTask(f) } } @@ -455,7 +460,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) receiver ! message timeout.getTimer.newTimeout(this, delay) } else { - system.eventStream.publish(Warning(this.getClass.getSimpleName, "Could not reschedule message to be sent because receiving actor has been terminated.")) + log.warning("Could not reschedule message to be sent because receiving actor has been terminated.") } } } @@ -464,7 +469,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) private def createContinuousTask(f: () ⇒ Unit, delay: Duration): TimerTask = { new TimerTask { def run(timeout: org.jboss.netty.akka.util.Timeout) { - system.dispatcher.dispatchTask(f) + dispatcher.dispatchTask(f) timeout.getTimer.newTimeout(this, delay) } } diff --git a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala index d66a66d3b1..83f88c1a61 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala @@ -302,7 +302,7 @@ class ActorSystemImpl(val name: String, val applicationConfig: Config) extends A eventStream.startStdoutLogger(settings) val log = new BusLogging(eventStream, "ActorSystem") // “this” used only for .getClass in tagging messages - val scheduler = new DefaultScheduler(new HashedWheelTimer(log, Executors.defaultThreadFactory, settings.SchedulerTickDuration, settings.SchedulerTicksPerWheel), this) + val scheduler = createScheduler() val provider: ActorRefProvider = { val providerClass = ReflectiveAccess.getClassFor(ProviderClass) match { @@ -336,6 +336,7 @@ class ActorSystemImpl(val name: String, val applicationConfig: Config) extends A } val dispatcherFactory = new Dispatchers(settings, DefaultDispatcherPrerequisites(eventStream, deadLetterMailbox, scheduler)) + // TODO why implicit val dispatcher? implicit val dispatcher = dispatcherFactory.defaultGlobalDispatcher //FIXME Set this to a Failure when things bubble to the top @@ -376,10 +377,32 @@ class ActorSystemImpl(val name: String, val applicationConfig: Config) extends A // TODO shutdown all that other stuff, whatever that may be def stop() { guardian.stop() - terminationFuture onComplete (_ ⇒ scheduler.stop()) + terminationFuture onComplete (_ ⇒ stopScheduler()) terminationFuture onComplete (_ ⇒ dispatcher.shutdown()) } + protected def createScheduler(): Scheduler = { + val threadFactory = new MonitorableThreadFactory("DefaultScheduler") + val hwt = new HashedWheelTimer(log, threadFactory, settings.SchedulerTickDuration, settings.SchedulerTicksPerWheel) + // note that dispatcher is by-name parameter in DefaultScheduler constructor, + // because dispatcher is not initialized when the scheduler is created + def safeDispatcher = { + if (dispatcher eq null) { + val exc = new IllegalStateException("Scheduler is using dispatcher before it has been initialized") + log.error(exc, exc.getMessage) + throw exc + } else { + dispatcher + } + } + new DefaultScheduler(hwt, log, safeDispatcher) + } + + protected def stopScheduler(): Unit = scheduler match { + case x: DefaultScheduler ⇒ x.stop() + case _ ⇒ + } + private val extensions = new ConcurrentIdentityHashMap[ExtensionId[_], AnyRef] /** From 823a68ac0f77bac7c4a67f643ad50073051e0d2a Mon Sep 17 00:00:00 2001 From: Henrik Engstrom Date: Fri, 25 Nov 2011 14:49:09 +0100 Subject: [PATCH 04/23] Updated samples and tutorial to Akka 2.0. Added projects to SBT project file. Fixes #1278 --- .../akka/routing/ConnectionManager.scala | 5 + .../src/main/scala/akka/routing/Routing.scala | 13 +- .../remote/netty/NettyRemoteSupport.scala | 4 +- .../akka/remote/NetworkFailureSpec.scala | 6 +- akka-samples/akka-sample-ants/README.md | 6 +- .../src/main/scala/Ants.scala | 67 +-- .../src/main/scala/sample/camel/Actors.scala | 322 +++++------ .../src/main/scala/sample/camel/Boot.scala | 196 +++---- .../sample/camel/ClientApplication.scala | 60 ++- .../sample/camel/ServerApplication.scala | 56 +- .../sample/camel/StandaloneApplication.scala | 256 ++++----- .../src/main/scala/ChatServer.scala | 505 +++++++++--------- akka-samples/akka-sample-fsm/src/README | 30 ++ .../src/main/scala/Buncher.scala | 21 +- .../main/scala/DiningHakkersOnBecome.scala | 35 +- .../src/main/scala/DiningHakkersOnFsm.scala | 33 +- .../akka-sample-hello/config/akka.conf | 27 - .../config/microkernel-server.xml | 65 --- akka-samples/akka-sample-hello/src/README | 28 + .../src/main/scala/sample/hello/Boot.scala | 14 - .../scala/sample/hello/HelloEndpoint.scala | 29 - .../src/main/scala/sample/hello/Main.scala | 32 ++ .../src/main/scala/OsgiExample.scala | 14 +- .../ServerManagedRemoteActorSample.scala | 64 +-- akka-tutorials/akka-tutorial-first/pom.xml | 2 +- .../project/TutorialBuild.scala | 22 + .../project/build.properties | 6 +- .../project/build/Project.scala | 3 - .../project/plugins/Plugins.scala | 6 - .../java/akka/tutorial/first/java/Pi.java | 290 +++++----- .../src/main/scala/Pi.scala | 175 +++--- .../src/test/scala/WorkerSpec.scala | 26 + project/AkkaBuild.scala | 82 +-- 33 files changed, 1291 insertions(+), 1209 deletions(-) create mode 100644 akka-samples/akka-sample-fsm/src/README delete mode 100644 akka-samples/akka-sample-hello/config/akka.conf delete mode 100644 akka-samples/akka-sample-hello/config/microkernel-server.xml create mode 100644 akka-samples/akka-sample-hello/src/README delete mode 100644 akka-samples/akka-sample-hello/src/main/scala/sample/hello/Boot.scala delete mode 100644 akka-samples/akka-sample-hello/src/main/scala/sample/hello/HelloEndpoint.scala create mode 100644 akka-samples/akka-sample-hello/src/main/scala/sample/hello/Main.scala create mode 100644 akka-tutorials/akka-tutorial-first/project/TutorialBuild.scala delete mode 100644 akka-tutorials/akka-tutorial-first/project/build/Project.scala delete mode 100644 akka-tutorials/akka-tutorial-first/project/plugins/Plugins.scala create mode 100644 akka-tutorials/akka-tutorial-first/src/test/scala/WorkerSpec.scala diff --git a/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala b/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala index b7655e376e..e8649dc3db 100644 --- a/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala +++ b/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala @@ -11,6 +11,7 @@ import scala.annotation.tailrec import java.util.concurrent.atomic.{ AtomicReference, AtomicInteger } import java.net.InetSocketAddress import akka.remote.RemoteAddress +import collection.JavaConverters /** * An Iterable that also contains a version. @@ -85,6 +86,10 @@ trait ConnectionManager { */ class LocalConnectionManager(initialConnections: Iterable[ActorRef]) extends ConnectionManager { + def this(linkedList: java.util.LinkedList[ActorRef]) { + this(JavaConverters.iterableAsScalaIterableConverter(linkedList).asScala) + } + case class State(version: Long, connections: Iterable[ActorRef]) extends VersionedIterable[ActorRef] { def iterable = connections } diff --git a/akka-actor/src/main/scala/akka/routing/Routing.scala b/akka-actor/src/main/scala/akka/routing/Routing.scala index 0dc6366cb1..8257002a42 100644 --- a/akka-actor/src/main/scala/akka/routing/Routing.scala +++ b/akka-actor/src/main/scala/akka/routing/Routing.scala @@ -14,6 +14,7 @@ import java.lang.reflect.InvocationTargetException import java.util.concurrent.atomic.{ AtomicReference, AtomicInteger } import scala.annotation.tailrec +import akka.japi.Creator sealed trait RouterType @@ -66,11 +67,17 @@ object RouterType { * Contains the configuration to create local and clustered routed actor references. * Routed ActorRef configuration object, this is thread safe and fully sharable. */ -case class RoutedProps private[akka] ( +private[akka] case class RoutedProps( routerFactory: () ⇒ Router = RoutedProps.defaultRouterFactory, connectionManager: ConnectionManager = new LocalConnectionManager(List()), timeout: Timeout = RoutedProps.defaultTimeout, localOnly: Boolean = RoutedProps.defaultLocalOnly) { + + // Java API + def this(creator: Creator[Router], connectionManager: ConnectionManager, timeout: Timeout, localOnly: Boolean) { + this(() ⇒ creator.create(), connectionManager, timeout, localOnly) + } + } object RoutedProps { @@ -167,7 +174,7 @@ abstract private[akka] class AbstractRoutedActorRef(val system: ActorSystem, val * A RoutedActorRef is an ActorRef that has a set of connected ActorRef and it uses a Router to send a message to * on (or more) of these actors. */ -private[akka] class RoutedActorRef(system: ActorSystem, val routedProps: RoutedProps, val supervisor: ActorRef, override val name: String) extends AbstractRoutedActorRef(system, routedProps) { +class RoutedActorRef(system: ActorSystem, val routedProps: RoutedProps, val supervisor: ActorRef, override val name: String) extends AbstractRoutedActorRef(system, routedProps) { val path = supervisor.path / name @@ -346,7 +353,7 @@ class RandomRouter extends BasicRouter { * * @author Jonas Bonér */ -class RoundRobinRouter extends BasicRouter { +private[akka] class RoundRobinRouter extends BasicRouter { private val state = new AtomicReference[RoundRobinState] 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 eedf58fd9e..9424b93372 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -95,8 +95,8 @@ abstract class RemoteClient private[akka] ( } class PassiveRemoteClient(val currentChannel: Channel, - remoteSupport: NettyRemoteSupport, - remoteAddress: RemoteAddress) + remoteSupport: NettyRemoteSupport, + remoteAddress: RemoteAddress) extends RemoteClient(remoteSupport, remoteAddress) { def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = runSwitch switchOn { diff --git a/akka-remote/src/test/scala/akka/remote/NetworkFailureSpec.scala b/akka-remote/src/test/scala/akka/remote/NetworkFailureSpec.scala index 7f7072b427..56a27079ea 100644 --- a/akka-remote/src/test/scala/akka/remote/NetworkFailureSpec.scala +++ b/akka-remote/src/test/scala/akka/remote/NetworkFailureSpec.scala @@ -20,7 +20,7 @@ trait NetworkFailureSpec { self: AkkaSpec ⇒ val BytesPerSecond = "60KByte/s" val DelayMillis = "350ms" - val PortRang = "1024-65535" + val PortRange = "1024-65535" def replyWithTcpResetFor(duration: Duration, dead: AtomicBoolean) = { Future { @@ -82,12 +82,12 @@ trait NetworkFailureSpec { self: AkkaSpec ⇒ def enableNetworkDrop() = { restoreIP() - assert(new ProcessBuilder("ipfw", "add", "1", "deny", "tcp", "from", "any", "to", "any", PortRang).start.waitFor == 0) + assert(new ProcessBuilder("ipfw", "add", "1", "deny", "tcp", "from", "any", "to", "any", PortRange).start.waitFor == 0) } def enableTcpReset() = { restoreIP() - assert(new ProcessBuilder("ipfw", "add", "1", "reset", "tcp", "from", "any", "to", "any", PortRang).start.waitFor == 0) + assert(new ProcessBuilder("ipfw", "add", "1", "reset", "tcp", "from", "any", "to", "any", PortRange).start.waitFor == 0) } def restoreIP() = { diff --git a/akka-samples/akka-sample-ants/README.md b/akka-samples/akka-sample-ants/README.md index 3c559834cb..5a416e0ba4 100644 --- a/akka-samples/akka-sample-ants/README.md +++ b/akka-samples/akka-sample-ants/README.md @@ -39,8 +39,8 @@ By using this software in any fashion, you are agreeing to be bound by the terms of this license. You must not remove this notice, or any other, from this software. -[ants.clj]:http://clojure.googlegroups.com/web/ants.clj -[akka]:http://akkasource.org -[spde]:http://technically.us/spde/ +[ants.clj]: http://clojure.googlegroups.com/web/ants.clj +[akka]: http://akka.io +[spde]: http://technically.us/spde/ [sbt]: http://code.google.com/p/simple-build-tool/ [cpl]: http://opensource.org/licenses/cpl1.0.php \ No newline at end of file diff --git a/akka-samples/akka-sample-ants/src/main/scala/Ants.scala b/akka-samples/akka-sample-ants/src/main/scala/Ants.scala index a6aae6f8bd..4b9cd8dd88 100644 --- a/akka-samples/akka-sample-ants/src/main/scala/Ants.scala +++ b/akka-samples/akka-sample-ants/src/main/scala/Ants.scala @@ -4,22 +4,23 @@ package sample.ants +import scala.util.Random.{ nextInt ⇒ randomInt } +import akka.actor.{ ActorSystem, Actor, ActorRef } +import akka.util.Duration +import akka.util.duration._ import java.util.concurrent.TimeUnit -import scala.util.Random.{nextInt => randomInt} -import akka.actor.{Actor, ActorRef, Scheduler} -import akka.actor.Actor.actorOf import akka.stm._ object Config { - val Dim = 80 // dimensions of square world - val AntsSqrt = 20 // number of ants = AntsSqrt^2 - val FoodPlaces = 35 // number of places with food - val FoodRange = 100 // range of amount of food at a place - val PherScale = 10 // scale factor for pheromone drawing - val AntMillis = 100 // how often an ant behaves (milliseconds) - val EvapMillis = 1000 // how often pheromone evaporation occurs (milliseconds) - val EvapRate = 0.99f // pheromone evaporation rate - val StartDelay = 1000 // delay before everything kicks off (milliseconds) + val Dim = 80 // dimensions of square world + val AntsSqrt = 20 // number of ants = AntsSqrt^2 + val FoodPlaces = 35 // number of places with food + val FoodRange = 100 // range of amount of food at a place + val PherScale = 10 // scale factor for pheromone drawing + val AntMillis = 100 // how often an ant behaves (milliseconds) + val EvapMillis = 1000 // how often pheromone evaporation occurs (milliseconds) + val EvapRate = 0.99f // pheromone evaporation rate + val StartDelay = 1000 milliseconds // delay before everything kicks off (milliseconds) } case class Ant(dir: Int, food: Boolean = false) { @@ -32,7 +33,7 @@ case class Ant(dir: Int, food: Boolean = false) { case class Cell(food: Int = 0, pher: Float = 0, ant: Option[Ant] = None, home: Boolean = false) { def addFood(i: Int) = copy(food = food + i) def addPher(x: Float) = copy(pher = pher + x) - def alterPher(f: Float => Float) = copy(pher = f(pher)) + def alterPher(f: Float ⇒ Float) = copy(pher = f(pher)) def putAnt(antOpt: Option[Ant]) = copy(ant = antOpt) def makeHome = copy(home = true) } @@ -45,10 +46,10 @@ class Place(initCell: Cell = EmptyCell) extends Ref(initCell) { def food(i: Int) = alter(_.addFood(i)) def hasFood = food > 0 def pher: Float = cell.pher - def pher(f: Float => Float) = alter(_.alterPher(f)) + def pher(f: Float ⇒ Float) = alter(_.alterPher(f)) def trail = alter(_.addPher(1)) def ant: Option[Ant] = cell.ant - def ant(f: Ant => Ant): Cell = alter(_.putAnt(ant map f)) + def ant(f: Ant ⇒ Ant): Cell = alter(_.putAnt(ant map f)) def enter(antOpt: Option[Ant]): Cell = alter(_.putAnt(antOpt)) def enter(ant: Ant): Cell = enter(Some(ant)) def leave = enter(None) @@ -62,10 +63,12 @@ case object Ping object World { import Config._ + val system = ActorSystem() + val homeOff = Dim / 4 lazy val places = Vector.fill(Dim, Dim)(new Place) lazy val ants = setup - lazy val evaporator = actorOf[Evaporator] + lazy val evaporator = system.actorOf[Evaporator] private val snapshotFactory = TransactionFactory(readonly = true, familyName = "snapshot") @@ -74,14 +77,14 @@ object World { def place(loc: (Int, Int)) = places(loc._1)(loc._2) private def setup = atomic { - for (i <- 1 to FoodPlaces) { + for (i ← 1 to FoodPlaces) { place(randomInt(Dim), randomInt(Dim)) food (randomInt(FoodRange)) } val homeRange = homeOff until (AntsSqrt + homeOff) - for (x <- homeRange; y <- homeRange) yield { + for (x ← homeRange; y ← homeRange) yield { place(x, y).makeHome place(x, y) enter Ant(randomInt(8)) - actorOf(new AntActor(x, y)) + system.actorOf(new AntActor(x, y)) } } @@ -91,7 +94,7 @@ object World { } private def pingEvery(millis: Long)(actor: ActorRef) = - Scheduler.schedule(actor, Ping, Config.StartDelay, millis, TimeUnit.MILLISECONDS) + system.scheduler.schedule(actor, Ping, Config.StartDelay, Duration(millis, TimeUnit.MILLISECONDS)) } object Util { @@ -106,13 +109,13 @@ object Util { def dimBound(n: Int) = bound(Dim, n) val dirDelta = Map(0 -> (0, -1), 1 -> (1, -1), 2 -> (1, 0), 3 -> (1, 1), - 4 -> (0, 1), 5 -> (-1, 1), 6 -> (-1, 0), 7 -> (-1, -1)) + 4 -> (0, 1), 5 -> (-1, 1), 6 -> (-1, 0), 7 -> (-1, -1)) def deltaLoc(x: Int, y: Int, dir: Int) = { val (dx, dy) = dirDelta(dirBound(dir)) (dimBound(x + dx), dimBound(y + dy)) } - def rankBy[A, B: Ordering](xs: Seq[A], f: A => B) = Map(xs.sortBy(f).zip(Stream from 1): _*) + def rankBy[A, B: Ordering](xs: Seq[A], f: A ⇒ B) = Map(xs.sortBy(f).zip(Stream from 1): _*) def roulette(slices: Seq[Int]) = { val total = slices.sum @@ -128,7 +131,7 @@ object Util { trait WorldActor extends Actor { def act - def receive = { case Ping => act } + def receive = { case Ping ⇒ act } } class AntActor(initLoc: (Int, Int)) extends WorldActor { @@ -140,8 +143,8 @@ class AntActor(initLoc: (Int, Int)) extends WorldActor { val name = "ant-from-" + initLoc._1 + "-" + initLoc._2 implicit val txFactory = TransactionFactory(familyName = name) - val homing = (p: Place) => p.pher + (100 * (if (p.home) 0 else 1)) - val foraging = (p: Place) => p.pher + p.food + val homing = (p: Place) ⇒ p.pher + (100 * (if (p.home) 0 else 1)) + val foraging = (p: Place) ⇒ p.pher + p.food def loc = locRef.getOrElse(initLoc) def newLoc(l: (Int, Int)) = locRef swap l @@ -149,7 +152,7 @@ class AntActor(initLoc: (Int, Int)) extends WorldActor { def act = atomic { val (x, y) = loc val current = place(x, y) - for (ant <- current.ant) { + for (ant ← current.ant) { val ahead = place(deltaLoc(x, y, ant.dir)) if (ant.food) { // homing if (current.home) dropFood @@ -166,7 +169,7 @@ class AntActor(initLoc: (Int, Int)) extends WorldActor { def move = { val (x, y) = loc val from = place(x, y) - for (ant <- from.ant) { + for (ant ← from.ant) { val toLoc = deltaLoc(x, y, ant.dir) val to = place(toLoc) to enter ant @@ -188,11 +191,11 @@ class AntActor(initLoc: (Int, Int)) extends WorldActor { current ant (_.dropOff.turnAround) } - def random[A: Ordering](ranking: Place => A) = { + def random[A: Ordering](ranking: Place ⇒ A) = { val (x, y) = loc val current = place(x, y) - for (ant <- current.ant) { - val delta = (turn: Int) => place(deltaLoc(x, y, ant.dir + turn)) + for (ant ← current.ant) { + val delta = (turn: Int) ⇒ place(deltaLoc(x, y, ant.dir + turn)) val ahead = delta(0) val aheadLeft = delta(-1) val aheadRight = delta(+1) @@ -211,9 +214,9 @@ class Evaporator extends WorldActor { import World._ implicit val txFactory = TransactionFactory(familyName = "evaporator") - val evaporate = (pher: Float) => pher * EvapRate + val evaporate = (pher: Float) ⇒ pher * EvapRate - def act = for (x <- 0 until Dim; y <- 0 until Dim) { + def act = for (x ← 0 until Dim; y ← 0 until Dim) { atomic { place(x, y) pher evaporate } } } diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Actors.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Actors.scala index f4655c3985..c091d7dfd8 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Actors.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Actors.scala @@ -1,161 +1,167 @@ -package sample.camel - -import org.apache.camel.Exchange - -import akka.actor.{ Actor, ActorRef, ActorRegistry } -import akka.camel.{ Ack, Failure, Producer, Message, Consumer } - /** - * Client-initiated remote actor. - */ -class RemoteActor1 extends Actor with Consumer { - def endpointUri = "jetty:http://localhost:6644/camel/remote-actor-1" + * Copyright (C) 2009-2010 Typesafe Inc. . + */ - protected def receive = { - case msg: Message ⇒ sender ! Message("hello %s" format msg.bodyAs[String], Map("sender" -> "remote1")) - } -} +// CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 -/** - * Server-initiated remote actor. - */ -class RemoteActor2 extends Actor with Consumer { - def endpointUri = "jetty:http://localhost:6644/camel/remote-actor-2" - - protected def receive = { - case msg: Message ⇒ sender ! Message("hello %s" format msg.bodyAs[String], Map("sender" -> "remote2")) - } -} - -class Producer1 extends Actor with Producer { - def endpointUri = "direct:welcome" - override def oneway = false // default -} - -class Consumer1 extends Actor with Consumer { - def endpointUri = "file:data/input/actor" - - def receive = { - case msg: Message ⇒ println("received %s" format msg.bodyAs[String]) - } -} - -class Consumer2 extends Actor with Consumer { - def endpointUri = "jetty:http://0.0.0.0:8877/camel/default" - - def receive = { - case msg: Message ⇒ sender ! ("Hello %s" format msg.bodyAs[String]) - } -} - -class Consumer3(transformer: ActorRef) extends Actor with Consumer { - def endpointUri = "jetty:http://0.0.0.0:8877/camel/welcome" - - def receive = { - case msg: Message ⇒ transformer.forward(msg.setBodyAs[String]) - } -} - -class Consumer4 extends Actor with Consumer { - def endpointUri = "jetty:http://0.0.0.0:8877/camel/stop" - - def receive = { - case msg: Message ⇒ msg.bodyAs[String] match { - case "stop" ⇒ { - sender ! "Consumer4 stopped" - self.stop - } - case body ⇒ sender ! body - } - } -} - -class Consumer5 extends Actor with Consumer { - def endpointUri = "jetty:http://0.0.0.0:8877/camel/start" - - def receive = { - case _ ⇒ { - Actor.actorOf[Consumer4] - sender ! "Consumer4 started" - } - } -} - -class Transformer(producer: ActorRef) extends Actor { - protected def receive = { - case msg: Message ⇒ producer.forward(msg.transformBody((body: String) ⇒ "- %s -" format body)) - } -} - -class Subscriber(name: String, uri: String) extends Actor with Consumer { - def endpointUri = uri - - protected def receive = { - case msg: Message ⇒ println("%s received: %s" format (name, msg.body)) - } -} - -class Publisher(uri: String) extends Actor with Producer { - def endpointUri = uri - override def oneway = true -} - -class PublisherBridge(uri: String, publisher: ActorRef) extends Actor with Consumer { - def endpointUri = uri - - protected def receive = { - case msg: Message ⇒ { - publisher ! msg.bodyAs[String] - sender ! "message published" - } - } -} - -class HttpConsumer(producer: ActorRef) extends Actor with Consumer { - def endpointUri = "jetty:http://0.0.0.0:8875/" - - protected def receive = { - case msg ⇒ producer forward msg - } -} - -class HttpProducer(transformer: ActorRef) extends Actor with Producer { - def endpointUri = "jetty://http://akka.io/?bridgeEndpoint=true" - - override protected def receiveBeforeProduce = { - // only keep Exchange.HTTP_PATH message header (which needed by bridge endpoint) - case msg: Message ⇒ msg.setHeaders(msg.headers(Set(Exchange.HTTP_PATH))) - } - - override protected def receiveAfterProduce = { - // do not reply but forward result to transformer - case msg ⇒ transformer forward msg - } -} - -class HttpTransformer extends Actor { - protected def receive = { - case msg: Message ⇒ sender ! (msg.transformBody { body: String ⇒ body replaceAll ("Akka ", "AKKA ") }) - case msg: Failure ⇒ sender ! msg - } -} - -class FileConsumer extends Actor with Consumer { - def endpointUri = "file:data/input/actor?delete=true" - override def autoack = false - - var counter = 0 - - def receive = { - case msg: Message ⇒ { - if (counter == 2) { - println("received %s" format msg.bodyAs[String]) - sender ! Ack - } else { - println("rejected %s" format msg.bodyAs[String]) - counter += 1 - sender ! Failure(new Exception("message number %s not accepted" format counter)) - } - } - } -} +//package sample.camel +// +//import org.apache.camel.Exchange +// +//import akka.actor.{ Actor, ActorRef, ActorRegistry } +//import akka.camel.{ Ack, Failure, Producer, Message, Consumer } +// +///** +// * Client-initiated remote actor. +// */ +//class RemoteActor1 extends Actor with Consumer { +// def endpointUri = "jetty:http://localhost:6644/camel/remote-actor-1" +// +// protected def receive = { +// case msg: Message ⇒ sender ! Message("hello %s" format msg.bodyAs[String], Map("sender" -> "remote1")) +// } +//} +// +///** +// * Server-initiated remote actor. +// */ +//class RemoteActor2 extends Actor with Consumer { +// def endpointUri = "jetty:http://localhost:6644/camel/remote-actor-2" +// +// protected def receive = { +// case msg: Message ⇒ sender ! Message("hello %s" format msg.bodyAs[String], Map("sender" -> "remote2")) +// } +//} +// +//class Producer1 extends Actor with Producer { +// def endpointUri = "direct:welcome" +// override def oneway = false // default +//} +// +//class Consumer1 extends Actor with Consumer { +// def endpointUri = "file:data/input/actor" +// +// def receive = { +// case msg: Message ⇒ println("received %s" format msg.bodyAs[String]) +// } +//} +// +//class Consumer2 extends Actor with Consumer { +// def endpointUri = "jetty:http://0.0.0.0:8877/camel/default" +// +// def receive = { +// case msg: Message ⇒ sender ! ("Hello %s" format msg.bodyAs[String]) +// } +//} +// +//class Consumer3(transformer: ActorRef) extends Actor with Consumer { +// def endpointUri = "jetty:http://0.0.0.0:8877/camel/welcome" +// +// def receive = { +// case msg: Message ⇒ transformer.forward(msg.setBodyAs[String]) +// } +//} +// +//class Consumer4 extends Actor with Consumer { +// def endpointUri = "jetty:http://0.0.0.0:8877/camel/stop" +// +// def receive = { +// case msg: Message ⇒ msg.bodyAs[String] match { +// case "stop" ⇒ { +// sender ! "Consumer4 stopped" +// self.stop +// } +// case body ⇒ sender ! body +// } +// } +//} +// +//class Consumer5 extends Actor with Consumer { +// def endpointUri = "jetty:http://0.0.0.0:8877/camel/start" +// +// def receive = { +// case _ ⇒ { +// Actor.actorOf[Consumer4] +// sender ! "Consumer4 started" +// } +// } +//} +// +//class Transformer(producer: ActorRef) extends Actor { +// protected def receive = { +// case msg: Message ⇒ producer.forward(msg.transformBody((body: String) ⇒ "- %s -" format body)) +// } +//} +// +//class Subscriber(name: String, uri: String) extends Actor with Consumer { +// def endpointUri = uri +// +// protected def receive = { +// case msg: Message ⇒ println("%s received: %s" format (name, msg.body)) +// } +//} +// +//class Publisher(uri: String) extends Actor with Producer { +// def endpointUri = uri +// override def oneway = true +//} +// +//class PublisherBridge(uri: String, publisher: ActorRef) extends Actor with Consumer { +// def endpointUri = uri +// +// protected def receive = { +// case msg: Message ⇒ { +// publisher ! msg.bodyAs[String] +// sender ! "message published" +// } +// } +//} +// +//class HttpConsumer(producer: ActorRef) extends Actor with Consumer { +// def endpointUri = "jetty:http://0.0.0.0:8875/" +// +// protected def receive = { +// case msg ⇒ producer forward msg +// } +//} +// +//class HttpProducer(transformer: ActorRef) extends Actor with Producer { +// def endpointUri = "jetty://http://akka.io/?bridgeEndpoint=true" +// +// override protected def receiveBeforeProduce = { +// // only keep Exchange.HTTP_PATH message header (which needed by bridge endpoint) +// case msg: Message ⇒ msg.setHeaders(msg.headers(Set(Exchange.HTTP_PATH))) +// } +// +// override protected def receiveAfterProduce = { +// // do not reply but forward result to transformer +// case msg ⇒ transformer forward msg +// } +//} +// +//class HttpTransformer extends Actor { +// protected def receive = { +// case msg: Message ⇒ sender ! (msg.transformBody { body: String ⇒ body replaceAll ("Akka ", "AKKA ") }) +// case msg: Failure ⇒ sender ! msg +// } +//} +// +//class FileConsumer extends Actor with Consumer { +// def endpointUri = "file:data/input/actor?delete=true" +// override def autoack = false +// +// var counter = 0 +// +// def receive = { +// case msg: Message ⇒ { +// if (counter == 2) { +// println("received %s" format msg.bodyAs[String]) +// sender ! Ack +// } else { +// println("rejected %s" format msg.bodyAs[String]) +// counter += 1 +// sender ! Failure(new Exception("message number %s not accepted" format counter)) +// } +// } +// } +//} diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala index b84dd9c1c9..31b76835a4 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala @@ -1,98 +1,104 @@ -package sample.camel - -import org.apache.camel.{ Exchange, Processor } -import org.apache.camel.builder.RouteBuilder -import org.apache.camel.impl.DefaultCamelContext -import org.apache.camel.spring.spi.ApplicationContextRegistry -import org.springframework.context.support.ClassPathXmlApplicationContext - -import akka.actor.Actor._ -import akka.actor.Props -import akka.actor.TypedActor -import akka.camel.CamelContextManager - /** - * @author Martin Krasser - */ -class Boot { + * Copyright (C) 2009-2010 Typesafe Inc. . + */ - // ----------------------------------------------------------------------- - // Basic example - // ----------------------------------------------------------------------- +// CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 - actorOf[Consumer1] - actorOf[Consumer2] - - // ----------------------------------------------------------------------- - // Custom Camel route example - // ----------------------------------------------------------------------- - - // Create CamelContext and a Spring-based registry - val context = new ClassPathXmlApplicationContext("/context-jms.xml", getClass) - val registry = new ApplicationContextRegistry(context) - - // Use a custom Camel context and a custom touter builder - CamelContextManager.init(new DefaultCamelContext(registry)) - CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder) - - val producer = actorOf[Producer1] - val mediator = actorOf(new Transformer(producer)) - val consumer = actorOf(new Consumer3(mediator)) - - // ----------------------------------------------------------------------- - // Asynchronous consumer-producer example (Akka homepage transformation) - // ----------------------------------------------------------------------- - - val httpTransformer = actorOf(new HttpTransformer) - val httpProducer = actorOf(new HttpProducer(httpTransformer)) - val httpConsumer = actorOf(new HttpConsumer(httpProducer)) - - // ----------------------------------------------------------------------- - // Publish subscribe examples - // ----------------------------------------------------------------------- - - // - // Cometd example commented out because camel-cometd is broken since Camel 2.3 - // - - //val cometdUri = "cometd://localhost:8111/test/abc?baseResource=file:target" - //val cometdSubscriber = actorOf(new Subscriber("cometd-subscriber", cometdUri)) - //val cometdPublisher = actorOf(new Publisher("cometd-publisher", cometdUri)) - - val jmsUri = "jms:topic:test" - val jmsSubscriber1 = actorOf(new Subscriber("jms-subscriber-1", jmsUri)) - val jmsSubscriber2 = actorOf(new Subscriber("jms-subscriber-2", jmsUri)) - val jmsPublisher = actorOf(new Publisher(jmsUri), "jms-publisher") - - //val cometdPublisherBridge = actorOf(new PublisherBridge("jetty:http://0.0.0.0:8877/camel/pub/cometd", cometdPublisher)) - val jmsPublisherBridge = actorOf(new PublisherBridge("jetty:http://0.0.0.0:8877/camel/pub/jms", jmsPublisher)) - - // ----------------------------------------------------------------------- - // Actor un-publishing and re-publishing example - // ----------------------------------------------------------------------- - - actorOf[Consumer4] // POSTing "stop" to http://0.0.0.0:8877/camel/stop stops and unpublishes this actor - actorOf[Consumer5] // POSTing any msg to http://0.0.0.0:8877/camel/start starts and published Consumer4 again. - - // ----------------------------------------------------------------------- - // Active object example - // ----------------------------------------------------------------------- - - // TODO: investigate why this consumer is not published - TypedActor.typedActorOf(classOf[TypedConsumer1], classOf[TypedConsumer1Impl], Props()) -} - -/** - * @author Martin Krasser - */ -class CustomRouteBuilder extends RouteBuilder { - def configure { - val actorUri = "actor:%s" format classOf[Consumer2].getName - from("jetty:http://0.0.0.0:8877/camel/custom").to(actorUri) - from("direct:welcome").process(new Processor() { - def process(exchange: Exchange) { - exchange.getOut.setBody("Welcome %s" format exchange.getIn.getBody) - } - }) - } -} +//package sample.camel +// +//import org.apache.camel.{ Exchange, Processor } +//import org.apache.camel.builder.RouteBuilder +//import org.apache.camel.impl.DefaultCamelContext +//import org.apache.camel.spring.spi.ApplicationContextRegistry +//import org.springframework.context.support.ClassPathXmlApplicationContext +// +//import akka.actor.Actor._ +//import akka.actor.Props +//import akka.actor.TypedActor +//import akka.camel.CamelContextManager +// +///** +// * @author Martin Krasser +// */ +//class Boot { +// +// // ----------------------------------------------------------------------- +// // Basic example +// // ----------------------------------------------------------------------- +// +// actorOf[Consumer1] +// actorOf[Consumer2] +// +// // ----------------------------------------------------------------------- +// // Custom Camel route example +// // ----------------------------------------------------------------------- +// +// // Create CamelContext and a Spring-based registry +// val context = new ClassPathXmlApplicationContext("/context-jms.xml", getClass) +// val registry = new ApplicationContextRegistry(context) +// +// // Use a custom Camel context and a custom touter builder +// CamelContextManager.init(new DefaultCamelContext(registry)) +// CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder) +// +// val producer = actorOf[Producer1] +// val mediator = actorOf(new Transformer(producer)) +// val consumer = actorOf(new Consumer3(mediator)) +// +// // ----------------------------------------------------------------------- +// // Asynchronous consumer-producer example (Akka homepage transformation) +// // ----------------------------------------------------------------------- +// +// val httpTransformer = actorOf(new HttpTransformer) +// val httpProducer = actorOf(new HttpProducer(httpTransformer)) +// val httpConsumer = actorOf(new HttpConsumer(httpProducer)) +// +// // ----------------------------------------------------------------------- +// // Publish subscribe examples +// // ----------------------------------------------------------------------- +// +// // +// // Cometd example commented out because camel-cometd is broken since Camel 2.3 +// // +// +// //val cometdUri = "cometd://localhost:8111/test/abc?baseResource=file:target" +// //val cometdSubscriber = actorOf(new Subscriber("cometd-subscriber", cometdUri)) +// //val cometdPublisher = actorOf(new Publisher("cometd-publisher", cometdUri)) +// +// val jmsUri = "jms:topic:test" +// val jmsSubscriber1 = actorOf(new Subscriber("jms-subscriber-1", jmsUri)) +// val jmsSubscriber2 = actorOf(new Subscriber("jms-subscriber-2", jmsUri)) +// val jmsPublisher = actorOf(new Publisher(jmsUri), "jms-publisher") +// +// //val cometdPublisherBridge = actorOf(new PublisherBridge("jetty:http://0.0.0.0:8877/camel/pub/cometd", cometdPublisher)) +// val jmsPublisherBridge = actorOf(new PublisherBridge("jetty:http://0.0.0.0:8877/camel/pub/jms", jmsPublisher)) +// +// // ----------------------------------------------------------------------- +// // Actor un-publishing and re-publishing example +// // ----------------------------------------------------------------------- +// +// actorOf[Consumer4] // POSTing "stop" to http://0.0.0.0:8877/camel/stop stops and unpublishes this actor +// actorOf[Consumer5] // POSTing any msg to http://0.0.0.0:8877/camel/start starts and published Consumer4 again. +// +// // ----------------------------------------------------------------------- +// // Active object example +// // ----------------------------------------------------------------------- +// +// // TODO: investigate why this consumer is not published +// TypedActor.typedActorOf(classOf[TypedConsumer1], classOf[TypedConsumer1Impl], Props()) +//} +// +///** +// * @author Martin Krasser +// */ +//class CustomRouteBuilder extends RouteBuilder { +// def configure { +// val actorUri = "actor:%s" format classOf[Consumer2].getName +// from("jetty:http://0.0.0.0:8877/camel/custom").to(actorUri) +// from("direct:welcome").process(new Processor() { +// def process(exchange: Exchange) { +// exchange.getOut.setBody("Welcome %s" format exchange.getIn.getBody) +// } +// }) +// } +//} diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ClientApplication.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ClientApplication.scala index c5662ea3b6..a4c5edf398 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ClientApplication.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ClientApplication.scala @@ -1,29 +1,35 @@ -package sample.camel - -import akka.actor.Actor._ -import akka.actor.TypedActor -import akka.camel.Message - /** - * @author Martin Krasser - */ -object ClientApplication extends App { - - /* TODO: fix remote example - - val actor1 = remote.actorOf[RemoteActor1]("localhost", 7777) - val actor2 = remote.actorFor("remote2", "localhost", 7777) - - val typedActor1 = - TypedActor.newRemoteInstance(classOf[RemoteTypedConsumer1],classOf[RemoteTypedConsumer1Impl], "localhost", 7777) - - val typedActor2 = remote.typedActorFor(classOf[RemoteTypedConsumer2], "remote3", "localhost", 7777) - - println(actor1 !! Message("actor1")) // activates and publishes actor remotely - println(actor2 !! Message("actor2")) // actor already activated and published remotely - - println(typedActor1.foo("x1", "y1")) // activates and publishes typed actor methods remotely - println(typedActor2.foo("x2", "y2")) // typed actor methods already activated and published remotely - + * Copyright (C) 2009-2010 Typesafe Inc. . */ -} + +// CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 + +//package sample.camel +// +//import akka.actor.Actor._ +//import akka.actor.TypedActor +//import akka.camel.Message +// +///** +// * @author Martin Krasser +// */ +//object ClientApplication extends App { +// +// /* TODO: fix remote example +// +// val actor1 = remote.actorOf[RemoteActor1]("localhost", 7777) +// val actor2 = remote.actorFor("remote2", "localhost", 7777) +// +// val typedActor1 = +// TypedActor.newRemoteInstance(classOf[RemoteTypedConsumer1],classOf[RemoteTypedConsumer1Impl], "localhost", 7777) +// +// val typedActor2 = remote.typedActorFor(classOf[RemoteTypedConsumer2], "remote3", "localhost", 7777) +// +// println(actor1 !! Message("actor1")) // activates and publishes actor remotely +// println(actor2 !! Message("actor2")) // actor already activated and published remotely +// +// println(typedActor1.foo("x1", "y1")) // activates and publishes typed actor methods remotely +// println(typedActor2.foo("x2", "y2")) // typed actor methods already activated and published remotely +// +// */ +//} diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ServerApplication.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ServerApplication.scala index aae7a61d99..1181e661d4 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ServerApplication.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ServerApplication.scala @@ -1,27 +1,33 @@ -package sample.camel - -import akka.actor.Actor._ -import akka.camel.CamelServiceManager -import akka.actor.{ TypedActor, Props } - /** - * @author Martin Krasser - */ -object ServerApplication extends App { - import CamelServiceManager._ - - /* TODO: fix remote example - - startCamelService - - val ua = actorOf[RemoteActor2] - val ta = TypedActor.typedActorOf( - classOf[RemoteTypedConsumer2], - classOf[RemoteTypedConsumer2Impl], Props()) - - remote.start("localhost", 7777) - remote.register("remote2", ua) - remote.registerTypedActor("remote3", ta) - + * Copyright (C) 2009-2010 Typesafe Inc. . */ -} + +// CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 + +//package sample.camel +// +//import akka.actor.Actor._ +//import akka.camel.CamelServiceManager +//import akka.actor.{ TypedActor, Props } +// +///** +// * @author Martin Krasser +// */ +//object ServerApplication extends App { +// import CamelServiceManager._ +// +// /* TODO: fix remote example +// +// startCamelService +// +// val ua = actorOf[RemoteActor2] +// val ta = TypedActor.typedActorOf( +// classOf[RemoteTypedConsumer2], +// classOf[RemoteTypedConsumer2Impl], Props()) +// +// remote.start("localhost", 7777) +// remote.register("remote2", ua) +// remote.registerTypedActor("remote3", ta) +// +// */ +//} diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/StandaloneApplication.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/StandaloneApplication.scala index 62506c5c5a..c87e6bdcab 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/StandaloneApplication.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/StandaloneApplication.scala @@ -1,128 +1,134 @@ -package sample.camel - -import org.apache.camel.impl.{ DefaultCamelContext, SimpleRegistry } -import org.apache.camel.builder.RouteBuilder -import org.apache.camel.spring.spi.ApplicationContextRegistry -import org.springframework.context.support.ClassPathXmlApplicationContext - -import akka.actor.{ Actor, TypedActor, Props } -import akka.camel._ - /** - * @author Martin Krasser - */ -object StandaloneApplication extends App { - import CamelContextManager._ - import CamelServiceManager._ + * Copyright (C) 2009-2010 Typesafe Inc. . + */ - // 'externally' register typed actors - val registry = new SimpleRegistry - registry.put("sample", TypedActor.typedActorOf(classOf[BeanIntf], classOf[BeanImpl], Props())) - - // customize CamelContext - CamelContextManager.init(new DefaultCamelContext(registry)) - CamelContextManager.mandatoryContext.addRoutes(new StandaloneApplicationRoute) - - startCamelService - - // access 'externally' registered typed actors - assert("hello msg1" == mandatoryContext.createProducerTemplate.requestBody("direct:test", "msg1")) - - mandatoryService.awaitEndpointActivation(1) { - // 'internally' register typed actor (requires CamelService) - TypedActor.typedActorOf(classOf[TypedConsumer2], classOf[TypedConsumer2Impl], Props()) - } - - // access 'internally' (automatically) registered typed-actors - // (see @consume annotation value at TypedConsumer2.foo method) - assert("default: msg3" == mandatoryContext.createProducerTemplate.requestBody("direct:default", "msg3")) - - stopCamelService - - Actor.registry.local.shutdownAll -} - -class StandaloneApplicationRoute extends RouteBuilder { - def configure = { - // route to typed actors (in SimpleRegistry) - from("direct:test").to("typed-actor:sample?method=foo") - } -} - -object StandaloneSpringApplication extends App { - import CamelContextManager._ - - // load Spring application context - val appctx = new ClassPathXmlApplicationContext("/context-standalone.xml") - - // We cannot use the CamelServiceManager to wait for endpoint activation - // because CamelServiceManager is started by the Spring application context. - // (and hence is not available for setting expectations on activations). This - // will be improved/enabled in upcoming releases. - Thread.sleep(1000) - - // access 'externally' registered typed actors with typed-actor component - assert("hello msg3" == mandatoryTemplate.requestBody("direct:test3", "msg3")) - - // access auto-started untyped consumer - assert("received msg3" == mandatoryTemplate.requestBody("direct:untyped-consumer-1", "msg3")) - - appctx.close - - Actor.registry.local.shutdownAll -} - -class StandaloneSpringApplicationRoute extends RouteBuilder { - def configure = { - // routes to typed actor (in ApplicationContextRegistry) - from("direct:test3").to("typed-actor:ta?method=foo") - } -} - -object StandaloneJmsApplication extends App { - import CamelServiceManager._ - - val context = new ClassPathXmlApplicationContext("/context-jms.xml") - val registry = new ApplicationContextRegistry(context) - - // Init CamelContextManager with custom CamelContext - CamelContextManager.init(new DefaultCamelContext(registry)) - - startCamelService - - val jmsUri = "jms:topic:test" - val jmsPublisher = Actor.actorOf(new Publisher(jmsUri), "jms-publisher") - - mandatoryService.awaitEndpointActivation(2) { - Actor.actorOf(new Subscriber("jms-subscriber-1", jmsUri)) - Actor.actorOf(new Subscriber("jms-subscriber-2", jmsUri)) - } - - // Send 10 messages to via publisher actor - for (i ← 1 to 10) { - jmsPublisher ! ("Akka rocks (%d)" format i) - } - - // Send 10 messages to JMS topic directly - for (i ← 1 to 10) { - CamelContextManager.mandatoryTemplate.sendBody(jmsUri, "Camel rocks (%d)" format i) - } - - // Wait a bit for subscribes to receive messages - Thread.sleep(1000) - - stopCamelService - Actor.registry.local.shutdownAll -} - -object StandaloneFileApplication { - import CamelServiceManager._ - - def main(args: Array[String]) { - startCamelService - mandatoryService.awaitEndpointActivation(1) { - Actor.actorOf(new FileConsumer) - } - } -} +// CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +//package sample.camel +// +//import org.apache.camel.impl.{ DefaultCamelContext, SimpleRegistry } +//import org.apache.camel.builder.RouteBuilder +//import org.apache.camel.spring.spi.ApplicationContextRegistry +//import org.springframework.context.support.ClassPathXmlApplicationContext +// +//import akka.actor.{ Actor, TypedActor, Props } +//import akka.camel._ +// +///** +// * @author Martin Krasser +// */ +//object StandaloneApplication extends App { +// import CamelContextManager._ +// import CamelServiceManager._ +// +// // 'externally' register typed actors +// val registry = new SimpleRegistry +// registry.put("sample", TypedActor.typedActorOf(classOf[BeanIntf], classOf[BeanImpl], Props())) +// +// // customize CamelContext +// CamelContextManager.init(new DefaultCamelContext(registry)) +// CamelContextManager.mandatoryContext.addRoutes(new StandaloneApplicationRoute) +// +// startCamelService +// +// // access 'externally' registered typed actors +// assert("hello msg1" == mandatoryContext.createProducerTemplate.requestBody("direct:test", "msg1")) +// +// mandatoryService.awaitEndpointActivation(1) { +// // 'internally' register typed actor (requires CamelService) +// TypedActor.typedActorOf(classOf[TypedConsumer2], classOf[TypedConsumer2Impl], Props()) +// } +// +// // access 'internally' (automatically) registered typed-actors +// // (see @consume annotation value at TypedConsumer2.foo method) +// assert("default: msg3" == mandatoryContext.createProducerTemplate.requestBody("direct:default", "msg3")) +// +// stopCamelService +// +// Actor.registry.local.shutdownAll +//} +// +//class StandaloneApplicationRoute extends RouteBuilder { +// def configure = { +// // route to typed actors (in SimpleRegistry) +// from("direct:test").to("typed-actor:sample?method=foo") +// } +//} +// +//object StandaloneSpringApplication extends App { +// import CamelContextManager._ +// +// // load Spring application context +// val appctx = new ClassPathXmlApplicationContext("/context-standalone.xml") +// +// // We cannot use the CamelServiceManager to wait for endpoint activation +// // because CamelServiceManager is started by the Spring application context. +// // (and hence is not available for setting expectations on activations). This +// // will be improved/enabled in upcoming releases. +// Thread.sleep(1000) +// +// // access 'externally' registered typed actors with typed-actor component +// assert("hello msg3" == mandatoryTemplate.requestBody("direct:test3", "msg3")) +// +// // access auto-started untyped consumer +// assert("received msg3" == mandatoryTemplate.requestBody("direct:untyped-consumer-1", "msg3")) +// +// appctx.close +// +// Actor.registry.local.shutdownAll +//} +// +//class StandaloneSpringApplicationRoute extends RouteBuilder { +// def configure = { +// // routes to typed actor (in ApplicationContextRegistry) +// from("direct:test3").to("typed-actor:ta?method=foo") +// } +//} +// +//object StandaloneJmsApplication extends App { +// import CamelServiceManager._ +// +// val context = new ClassPathXmlApplicationContext("/context-jms.xml") +// val registry = new ApplicationContextRegistry(context) +// +// // Init CamelContextManager with custom CamelContext +// CamelContextManager.init(new DefaultCamelContext(registry)) +// +// startCamelService +// +// val jmsUri = "jms:topic:test" +// val jmsPublisher = Actor.actorOf(new Publisher(jmsUri), "jms-publisher") +// +// mandatoryService.awaitEndpointActivation(2) { +// Actor.actorOf(new Subscriber("jms-subscriber-1", jmsUri)) +// Actor.actorOf(new Subscriber("jms-subscriber-2", jmsUri)) +// } +// +// // Send 10 messages to via publisher actor +// for (i ← 1 to 10) { +// jmsPublisher ! ("Akka rocks (%d)" format i) +// } +// +// // Send 10 messages to JMS topic directly +// for (i ← 1 to 10) { +// CamelContextManager.mandatoryTemplate.sendBody(jmsUri, "Camel rocks (%d)" format i) +// } +// +// // Wait a bit for subscribes to receive messages +// Thread.sleep(1000) +// +// stopCamelService +// Actor.registry.local.shutdownAll +//} +// +//object StandaloneFileApplication { +// import CamelServiceManager._ +// +// def main(args: Array[String]) { +// startCamelService +// mandatoryService.awaitEndpointActivation(1) { +// Actor.actorOf(new FileConsumer) +// } +// } +//} +// 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 d9b58ef771..49b5da2138 100644 --- a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala +++ b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala @@ -1,253 +1,256 @@ - /** - * Copyright (C) 2009-2010 Typesafe Inc. . - */ +/** + * Copyright (C) 2009-2010 Typesafe Inc. . + */ - package sample.chat - - import scala.collection.mutable.HashMap - - import akka.actor.{Actor, ActorRef, Props} - import akka.stm._ - import akka.actor.Actor._ - import akka.event.EventHandler - - /****************************************************************************** - Akka Chat Client/Server Sample Application - - How 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 console' to start up a REPL (interpreter). - 2. In the first REPL you get execute: - - scala> import sample.chat._ - - scala> import akka.actor.Actor._ - - scala> val chatService = actorOf[ChatService] - 3. In the second REPL you get execute: - - scala> import sample.chat._ - - scala> ClientRunner.run - 4. See the chat simulation run. - 5. Run it again to see full speed after first initialization. - 6. In the client REPL, or in a new REPL, you can also create your own client - - scala> import sample.chat._ - - scala> val myClient = new ChatClient("") - - scala> myClient.login - - scala> myClient.post("Can I join?") - - scala> println("CHAT LOG:\n\t" + myClient.chatLog.log.mkString("\n\t")) - - - That’s it. Have fun. - - ******************************************************************************/ - - /** - * ChatServer's internal events. - */ - sealed trait Event - case class Login(user: String) extends Event - case class Logout(user: String) extends Event - case class GetChatLog(from: String) extends Event - case class ChatLog(log: List[String]) extends Event - case class ChatMessage(from: String, message: String) extends Event - - /** - * Chat client. - */ - class ChatClient(val name: String) { - val chat = Actor.remote.actorFor("chat:service", "localhost", 2552) - - 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")) - } - - /** - * Internal chat client session. - */ - class Session(user: String, storage: ActorRef) extends Actor { - private val loginTime = System.currentTimeMillis - private var userLog: List[String] = Nil - - EventHandler.info(this, "New session for user [%s] has been created at [%s]".format(user, loginTime)) - - def receive = { - case msg @ ChatMessage(from, message) => - userLog ::= message - storage ! msg - - case msg @ GetChatLog(_) => - storage forward msg - } - } - - /** - * Abstraction of chat storage holding the chat log. - */ - trait ChatStorage extends Actor - - /** - * Memory-backed chat storage implementation. - */ - class MemoryChatStorage extends ChatStorage { - private var chatLog = TransactionalVector[Array[Byte]]() - - EventHandler.info(this, "Memory-based chat storage is starting up...") - - def receive = { - case msg @ ChatMessage(from, message) => - EventHandler.debug(this, "New chat message [%s]".format(message)) - atomic { chatLog + message.getBytes("UTF-8") } - - case GetChatLog(_) => - val messageList = atomic { chatLog.map(bytes => new String(bytes, "UTF-8")).toList } - reply(ChatLog(messageList)) - } - - override def postRestart(reason: Throwable) { - chatLog = TransactionalVector() - } - } - - /** - * Implements user session management. - *

- * Uses self-type annotation (this: Actor =>) to declare that it needs to be mixed in with an Actor. - */ - trait SessionManagement { this: Actor => - - val storage: ActorRef // needs someone to provide the ChatStorage - val sessions = new HashMap[String, ActorRef] - - protected def sessionManagement: Receive = { - case Login(username) => - EventHandler.info(this, "User [%s] has logged in".format(username)) - val session = actorOf(new Session(username, storage)) - session - sessions += (username -> session) - - case Logout(username) => - EventHandler.info(this, "User [%s] has logged out".format(username)) - val session = sessions(username) - session.stop() - sessions -= username - } - - protected def shutdownSessions() { - sessions.foreach { case (_, session) => session.stop() } - } - } - - /** - * Implements chat management, e.g. chat message dispatch. - *

- * Uses self-type annotation (this: Actor =>) to declare that it needs to be mixed in with an Actor. - */ - trait ChatManagement { this: Actor => - val sessions: HashMap[String, ActorRef] // needs someone to provide the Session map - - protected def chatManagement: Receive = { - case msg @ ChatMessage(from, _) => getSession(from).foreach(_ ! msg) - case msg @ GetChatLog(from) => getSession(from).foreach(_ forward msg) - } - - private def getSession(from: String) : Option[ActorRef] = { - if (sessions.contains(from)) - Some(sessions(from)) - else { - EventHandler.info(this, "Session expired for %s".format(from)) - None - } - } - } - - /** - * Creates and links a MemoryChatStorage. - */ - trait MemoryChatStorageFactory { this: Actor => - val storage = actorOf(Props[MemoryChatStorage].withSupervisor(this.self)) // starts and links ChatStorage - } - - /** - * Chat server. Manages sessions and redirects all other messages to the Session for the client. - */ - trait ChatServer extends Actor { - //faultHandler = OneForOneStrategy(List(classOf[Exception]),5, 5000) - val storage: ActorRef - - EventHandler.info(this, "Chat server is starting up...") - - // actor message handler - def receive: Receive = sessionManagement orElse chatManagement - - // abstract methods to be defined somewhere else - protected def chatManagement: Receive - protected def sessionManagement: Receive - protected def shutdownSessions() - - override def postStop() { - EventHandler.info(this, "Chat server is shutting down...") - shutdownSessions() - storage.stop() - } - } - - /** - * Class encapsulating the full Chat Service. - * Start service by invoking: - *

-   * val chatService = Actor.actorOf[ChatService]
-   * 
- */ - class ChatService extends - ChatServer with - SessionManagement with - ChatManagement with - MemoryChatStorageFactory { - override def preStart() { - remote.start("localhost", 2552); - remote.register("chat:service", self) //Register the actor with the specified service id - } - } - - /** - * Test runner starting ChatService. - */ - object ServerRunner { - - def main(args: Array[String]) { ServerRunner.run() } - - def run() { - actorOf[ChatService] - } - } - - /** - * Test runner emulating a chat session. - */ - object ClientRunner { - - def main(args: Array[String]) { ClientRunner.run() } - - def run() { - - val client1 = new ChatClient("jonas") - client1.login - val client2 = new ChatClient("patrik") - client2.login - - client1.post("Hi there") - println("CHAT LOG:\n\t" + client1.chatLog.log.mkString("\n\t")) - - client2.post("Hello") - println("CHAT LOG:\n\t" + client2.chatLog.log.mkString("\n\t")) - - client1.post("Hi again") - println("CHAT LOG:\n\t" + client1.chatLog.log.mkString("\n\t")) - - client1.logout - client2.logout - } - } +// REMOTING IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +// +// package sample.chat +// +// import scala.collection.mutable.HashMap +// +// import akka.actor.{Actor, ActorRef, Props} +// import akka.stm._ +// import akka.actor.Actor._ +// import akka.event.EventHandler +// +// /****************************************************************************** +// Akka Chat Client/Server Sample Application +// +// How 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 console' to start up a REPL (interpreter). +// 2. In the first REPL you get execute: +// - scala> import sample.chat._ +// - scala> import akka.actor.Actor._ +// - scala> val chatService = actorOf[ChatService] +// 3. In the second REPL you get execute: +// - scala> import sample.chat._ +// - scala> ClientRunner.run +// 4. See the chat simulation run. +// 5. Run it again to see full speed after first initialization. +// 6. In the client REPL, or in a new REPL, you can also create your own client +// - scala> import sample.chat._ +// - scala> val myClient = new ChatClient("") +// - scala> myClient.login +// - scala> myClient.post("Can I join?") +// - scala> println("CHAT LOG:\n\t" + myClient.chatLog.log.mkString("\n\t")) +// +// +// That’s it. Have fun. +// +// ******************************************************************************/ +// +// /** +// * ChatServer's internal events. +// */ +// sealed trait Event +// case class Login(user: String) extends Event +// case class Logout(user: String) extends Event +// case class GetChatLog(from: String) extends Event +// case class ChatLog(log: List[String]) extends Event +// case class ChatMessage(from: String, message: String) extends Event +// +// /** +// * Chat client. +// */ +// class ChatClient(val name: String) { +// val chat = Actor.remote.actorFor("chat:service", "localhost", 2552) +// +// 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")) +// } +// +// /** +// * Internal chat client session. +// */ +// class Session(user: String, storage: ActorRef) extends Actor { +// private val loginTime = System.currentTimeMillis +// private var userLog: List[String] = Nil +// +// EventHandler.info(this, "New session for user [%s] has been created at [%s]".format(user, loginTime)) +// +// def receive = { +// case msg @ ChatMessage(from, message) => +// userLog ::= message +// storage ! msg +// +// case msg @ GetChatLog(_) => +// storage forward msg +// } +// } +// +// /** +// * Abstraction of chat storage holding the chat log. +// */ +// trait ChatStorage extends Actor +// +// /** +// * Memory-backed chat storage implementation. +// */ +// class MemoryChatStorage extends ChatStorage { +// private var chatLog = TransactionalVector[Array[Byte]]() +// +// EventHandler.info(this, "Memory-based chat storage is starting up...") +// +// def receive = { +// case msg @ ChatMessage(from, message) => +// EventHandler.debug(this, "New chat message [%s]".format(message)) +// atomic { chatLog + message.getBytes("UTF-8") } +// +// case GetChatLog(_) => +// val messageList = atomic { chatLog.map(bytes => new String(bytes, "UTF-8")).toList } +// reply(ChatLog(messageList)) +// } +// +// override def postRestart(reason: Throwable) { +// chatLog = TransactionalVector() +// } +// } +// +// /** +// * Implements user session management. +// *

+// * Uses self-type annotation (this: Actor =>) to declare that it needs to be mixed in with an Actor. +// */ +// trait SessionManagement { this: Actor => +// +// val storage: ActorRef // needs someone to provide the ChatStorage +// val sessions = new HashMap[String, ActorRef] +// +// protected def sessionManagement: Receive = { +// case Login(username) => +// EventHandler.info(this, "User [%s] has logged in".format(username)) +// val session = actorOf(new Session(username, storage)) +// session +// sessions += (username -> session) +// +// case Logout(username) => +// EventHandler.info(this, "User [%s] has logged out".format(username)) +// val session = sessions(username) +// session.stop() +// sessions -= username +// } +// +// protected def shutdownSessions() { +// sessions.foreach { case (_, session) => session.stop() } +// } +// } +// +// /** +// * Implements chat management, e.g. chat message dispatch. +// *

+// * Uses self-type annotation (this: Actor =>) to declare that it needs to be mixed in with an Actor. +// */ +// trait ChatManagement { this: Actor => +// val sessions: HashMap[String, ActorRef] // needs someone to provide the Session map +// +// protected def chatManagement: Receive = { +// case msg @ ChatMessage(from, _) => getSession(from).foreach(_ ! msg) +// case msg @ GetChatLog(from) => getSession(from).foreach(_ forward msg) +// } +// +// private def getSession(from: String) : Option[ActorRef] = { +// if (sessions.contains(from)) +// Some(sessions(from)) +// else { +// EventHandler.info(this, "Session expired for %s".format(from)) +// None +// } +// } +// } +// +// /** +// * Creates and links a MemoryChatStorage. +// */ +// trait MemoryChatStorageFactory { this: Actor => +// val storage = actorOf(Props[MemoryChatStorage].withSupervisor(this.self)) // starts and links ChatStorage +// } +// +// /** +// * Chat server. Manages sessions and redirects all other messages to the Session for the client. +// */ +// trait ChatServer extends Actor { +// //faultHandler = OneForOneStrategy(List(classOf[Exception]),5, 5000) +// val storage: ActorRef +// +// EventHandler.info(this, "Chat server is starting up...") +// +// // actor message handler +// def receive: Receive = sessionManagement orElse chatManagement +// +// // abstract methods to be defined somewhere else +// protected def chatManagement: Receive +// protected def sessionManagement: Receive +// protected def shutdownSessions() +// +// override def postStop() { +// EventHandler.info(this, "Chat server is shutting down...") +// shutdownSessions() +// storage.stop() +// } +// } +// +// /** +// * Class encapsulating the full Chat Service. +// * Start service by invoking: +// *

+//   * val chatService = Actor.actorOf[ChatService]
+//   * 
+// */ +// class ChatService extends +// ChatServer with +// SessionManagement with +// ChatManagement with +// MemoryChatStorageFactory { +// override def preStart() { +// remote.start("localhost", 2552); +// remote.register("chat:service", self) //Register the actor with the specified service id +// } +// } +// +// /** +// * Test runner starting ChatService. +// */ +// object ServerRunner { +// +// def main(args: Array[String]) { ServerRunner.run() } +// +// def run() { +// actorOf[ChatService] +// } +// } +// +// /** +// * Test runner emulating a chat session. +// */ +// object ClientRunner { +// +// def main(args: Array[String]) { ClientRunner.run() } +// +// def run() { +// +// val client1 = new ChatClient("jonas") +// client1.login +// val client2 = new ChatClient("patrik") +// client2.login +// +// client1.post("Hi there") +// println("CHAT LOG:\n\t" + client1.chatLog.log.mkString("\n\t")) +// +// client2.post("Hello") +// println("CHAT LOG:\n\t" + client2.chatLog.log.mkString("\n\t")) +// +// client1.post("Hi again") +// println("CHAT LOG:\n\t" + client1.chatLog.log.mkString("\n\t")) +// +// client1.logout +// client2.logout +// } +// } +// diff --git a/akka-samples/akka-sample-fsm/src/README b/akka-samples/akka-sample-fsm/src/README new file mode 100644 index 0000000000..17971c005b --- /dev/null +++ b/akka-samples/akka-sample-fsm/src/README @@ -0,0 +1,30 @@ +FSM +=== + +Requirements +------------ + +To build and run FSM you need [Simple Build Tool][sbt] (sbt). + +Running +------- + +First time, 'sbt update' to get dependencies, then to run Ants use 'sbt run'. +Here is an example. First type 'sbt' to start SBT interactively, the run 'update' and 'run': +> cd $AKKA_HOME + +> % sbt + +> > update + +> > project akka-sample-fsm + +> > run + +> > Choose 1 or 2 depending on what sample you wish to run + +Notice +------ + +[akka]: http://akka.io +[sbt]: http://code.google.com/p/simple-build-tool/ diff --git a/akka-samples/akka-sample-fsm/src/main/scala/Buncher.scala b/akka-samples/akka-sample-fsm/src/main/scala/Buncher.scala index 0dcf33e401..d039609a98 100644 --- a/akka-samples/akka-sample-fsm/src/main/scala/Buncher.scala +++ b/akka-samples/akka-sample-fsm/src/main/scala/Buncher.scala @@ -1,3 +1,6 @@ +/** + * Copyright (C) 2009-2010 Typesafe Inc. . + */ package sample.fsm.buncher import akka.actor.ActorRefFactory @@ -6,15 +9,15 @@ import akka.util.Duration import akka.actor.{ FSM, Actor, ActorRef } /* - * generic typed object buncher. - * - * To instantiate it, use the factory method like so: - * Buncher(100, 500)(x : List[AnyRef] => x foreach println) - * which will yield a fully functional ActorRef. - * The type of messages allowed is strongly typed to match the - * supplied processing method; other messages are discarded (and - * possibly logged). - */ +* generic typed object buncher. +* +* To instantiate it, use the factory method like so: +* Buncher(100, 500)(x : List[AnyRef] => x foreach println) +* which will yield a fully functional ActorRef. +* The type of messages allowed is strongly typed to match the +* supplied processing method; other messages are discarded (and +* possibly logged). +*/ object GenericBuncher { trait State case object Idle extends State diff --git a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala index 2c23940c9f..3acbf473e6 100644 --- a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala +++ b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala @@ -1,3 +1,6 @@ +/** + * Copyright (C) 2009-2010 Typesafe Inc. . + */ package sample.fsm.dining.become //Akka adaptation of @@ -7,8 +10,8 @@ import akka.actor.{ ActorRef, Actor, ActorSystem } import akka.util.duration._ /* - * First we define our messages, they basically speak for themselves - */ +* First we define our messages, they basically speak for themselves +*/ sealed trait DiningHakkerMessage case class Busy(chopstick: ActorRef) extends DiningHakkerMessage case class Put(hakker: ActorRef) extends DiningHakkerMessage @@ -18,9 +21,9 @@ object Eat extends DiningHakkerMessage object Think extends DiningHakkerMessage /* - * A Chopstick is an actor, it can be taken, and put back - */ -class Chopstick(name: String) extends Actor { +* A Chopstick is an actor, it can be taken, and put back +*/ +class Chopstick extends Actor { //When a Chopstick is taken by a hakker //It will refuse to be taken by other hakkers @@ -44,8 +47,8 @@ class Chopstick(name: String) extends Actor { } /* - * A hakker is an awesome dude or dudett who either thinks about hacking or has to eat ;-) - */ +* A hakker is an awesome dude or dudett who either thinks about hacking or has to eat ;-) +*/ class Hakker(name: String, left: ActorRef, right: ActorRef) extends Actor { //When a hakker is thinking it can become hungry @@ -75,7 +78,7 @@ class Hakker(name: String, left: ActorRef, right: ActorRef) extends Actor { //back to think about how he should obtain his chopsticks :-) def waiting_for(chopstickToWaitFor: ActorRef, otherChopstick: ActorRef): Receive = { case Taken(`chopstickToWaitFor`) ⇒ - println("%s has picked up %s and %s, and starts to eat", name, left.address, right.address) + println("%s has picked up %s and %s and starts to eat".format(name, left.name, right.name)) become(eating) system.scheduler.scheduleOnce(self, Think, 5 seconds) @@ -105,27 +108,33 @@ class Hakker(name: String, left: ActorRef, right: ActorRef) extends Actor { become(thinking) left ! Put(self) right ! Put(self) - println("%s puts down his chopsticks and starts to think", name) + println("%s puts down his chopsticks and starts to think".format(name)) system.scheduler.scheduleOnce(self, Eat, 5 seconds) } //All hakkers start in a non-eating state def receive = { case Think ⇒ - println("%s starts to think", name) + println("%s starts to think".format(name)) become(thinking) system.scheduler.scheduleOnce(self, Eat, 5 seconds) } } /* - * Alright, here's our test-harness - */ +* Alright, here's our test-harness +*/ object DiningHakkers { val system = ActorSystem() + + def main(args: Array[String]) { + run + } + def run { //Create 5 chopsticks - val chopsticks = for (i ← 1 to 5) yield system.actorOf(new Chopstick("Chopstick " + i)) + val chopsticks = for (i ← 1 to 5) yield system.actorOf[Chopstick]("Chopstick " + i) + //Create 5 awesome hakkers and assign them their left and right chopstick val hakkers = for { (name, i) ← List("Ghosh", "Bonér", "Klang", "Krasser", "Manie").zipWithIndex diff --git a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala index 987f630784..d0c8bca54a 100644 --- a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala +++ b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala @@ -1,3 +1,6 @@ +/** + * Copyright (C) 2009-2010 Typesafe Inc. . + */ package sample.fsm.dining.fsm import akka.actor.{ ActorRef, Actor, FSM, ActorSystem } @@ -6,8 +9,8 @@ import akka.util.Duration import akka.util.duration._ /* - * Some messages for the chopstick - */ +* Some messages for the chopstick +*/ sealed trait ChopstickMessage object Take extends ChopstickMessage object Put extends ChopstickMessage @@ -27,9 +30,9 @@ case object Taken extends ChopstickState case class TakenBy(hakker: ActorRef) /* - * A chopstick is an actor, it can be taken, and put back - */ -class Chopstick(name: String) extends Actor with FSM[ChopstickState, TakenBy] { +* A chopstick is an actor, it can be taken, and put back +*/ +class Chopstick extends Actor with FSM[ChopstickState, TakenBy] { // A chopstick begins its existence as available and taken by no one startWith(Available, TakenBy(system.deadLetters)) @@ -77,8 +80,8 @@ case object Eating extends FSMHakkerState case class TakenChopsticks(left: Option[ActorRef], right: Option[ActorRef]) /* - * A fsm hakker is an awesome dude or dudette who either thinks about hacking or has to eat ;-) - */ +* A fsm hakker is an awesome dude or dudette who either thinks about hacking or has to eat ;-) +*/ class FSMHakker(name: String, left: ActorRef, right: ActorRef) extends Actor with FSM[FSMHakkerState, TakenChopsticks] { //All hakkers start waiting @@ -86,7 +89,7 @@ class FSMHakker(name: String, left: ActorRef, right: ActorRef) extends Actor wit when(Waiting) { case Event(Think, _) ⇒ - println("%s starts to think", name) + println("%s starts to think".format(name)) startThinking(5 seconds) } @@ -125,7 +128,7 @@ class FSMHakker(name: String, left: ActorRef, right: ActorRef) extends Actor wit } private def startEating(left: ActorRef, right: ActorRef): State = { - println("%s has picked up %s and %s, and starts to eat", name, left.address, right.address) + println("%s has picked up %s and %s and starts to eat".format(name, left.name, right.name)) goto(Eating) using TakenChopsticks(Some(left), Some(right)) forMax (5 seconds) } @@ -144,7 +147,7 @@ class FSMHakker(name: String, left: ActorRef, right: ActorRef) extends Actor wit // then he puts down his chopsticks and starts to think when(Eating) { case Event(StateTimeout, _) ⇒ - println("%s puts down his chopsticks and starts to think", name) + println("%s puts down his chopsticks and starts to think".format(name)) left ! Put right ! Put startThinking(5 seconds) @@ -159,15 +162,19 @@ class FSMHakker(name: String, left: ActorRef, right: ActorRef) extends Actor wit } /* - * Alright, here's our test-harness - */ +* Alright, here's our test-harness +*/ object DiningHakkersOnFsm { val system = ActorSystem() + def main(args: Array[String]) { + run + } + def run = { // Create 5 chopsticks - val chopsticks = for (i ← 1 to 5) yield system.actorOf(new Chopstick("Chopstick " + i)) + val chopsticks = for (i ← 1 to 5) yield system.actorOf[Chopstick]("Chopstick " + i) // Create 5 awesome fsm hakkers and assign them their left and right chopstick val hakkers = for { (name, i) ← List("Ghosh", "Bonér", "Klang", "Krasser", "Manie").zipWithIndex diff --git a/akka-samples/akka-sample-hello/config/akka.conf b/akka-samples/akka-sample-hello/config/akka.conf deleted file mode 100644 index 5b8920874f..0000000000 --- a/akka-samples/akka-sample-hello/config/akka.conf +++ /dev/null @@ -1,27 +0,0 @@ -#################### -# Akka Config File # -#################### - -akka { - version = "2.0-SNAPSHOT" - - enabled-modules = ["http"] - - time-unit = "seconds" - - event-handlers = ["akka.event.EventHandler$DefaultListener"] - - boot = ["sample.hello.Boot"] - - http { - hostname = "localhost" - port = 9998 - - connection-close = true - root-actor-id = "_httproot" - root-actor-builtin = true - timeout = 1000 - expired-header-name = "Async-Timeout" - expired-header-value = "expired" - } -} diff --git a/akka-samples/akka-sample-hello/config/microkernel-server.xml b/akka-samples/akka-sample-hello/config/microkernel-server.xml deleted file mode 100644 index 4f86dab23c..0000000000 --- a/akka-samples/akka-sample-hello/config/microkernel-server.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - 300000 - 2 - false - 8443 - 20000 - 5000 - - - - - - - - - - - - - - / - - akka.http.AkkaMistServlet - /* - - - - - - - - - - - - - - - true - true - true - 1000 - - diff --git a/akka-samples/akka-sample-hello/src/README b/akka-samples/akka-sample-hello/src/README new file mode 100644 index 0000000000..cd271f1dde --- /dev/null +++ b/akka-samples/akka-sample-hello/src/README @@ -0,0 +1,28 @@ +HELLO +===== + +Requirements +------------ + +To build and run FSM you need [Simple Build Tool][sbt] (sbt). + +Running +------- + +First time, 'sbt update' to get dependencies, then to run Ants use 'sbt run'. +Here is an example. First type 'sbt' to start SBT interactively, the run 'update' and 'run': +> cd $AKKA_HOME + +> % sbt + +> > update + +> > project akka-sample-hello + +> > run + +Notice +------ + +[akka]: http://akka.io +[sbt]: http://code.google.com/p/simple-build-tool/ diff --git a/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Boot.scala b/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Boot.scala deleted file mode 100644 index 149c6a3ee4..0000000000 --- a/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Boot.scala +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (C) 2009-2011 Typesafe Inc. - */ - -package sample.hello - -import akka.actor._ -import akka.http._ - -class Boot { - val supervisor = Supervisor(OneForOneStrategy(List(classOf[Exception]), 3, 100)) - Actor.actorOf(Props[RootEndpoint].withSupervisor(supervisor)) - Actor.actorOf(Props[HelloEndpoint].withSupervisor(supervisor)) -} diff --git a/akka-samples/akka-sample-hello/src/main/scala/sample/hello/HelloEndpoint.scala b/akka-samples/akka-sample-hello/src/main/scala/sample/hello/HelloEndpoint.scala deleted file mode 100644 index 2ea8c1fe83..0000000000 --- a/akka-samples/akka-sample-hello/src/main/scala/sample/hello/HelloEndpoint.scala +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (C) 2009-2011 Typesafe Inc. - */ - -package sample.hello - -import akka.actor._ -import akka.http._ - -import java.text.DateFormat -import java.util.Date - -class HelloEndpoint extends Actor with Endpoint { - self.dispatcher = Endpoint.Dispatcher - - lazy val hello = Actor.actorOf( - new Actor { - def time = DateFormat.getTimeInstance.format(new Date) - def receive = { - case get: Get => get OK "Hello at " + time - } - }) - - def hook: Endpoint.Hook = { case _ => hello } - - override def preStart = Actor.registry.actorFor(MistSettings.RootActorID).get ! Endpoint.Attach(hook) - - def receive = handleHttpRequest -} diff --git a/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Main.scala b/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Main.scala new file mode 100644 index 0000000000..e3399e86fc --- /dev/null +++ b/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Main.scala @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2009-2011 Typesafe Inc. + */ +package sample.hello + +import akka.actor.{ ActorSystem, Actor } + +case object Start + +object Main { + def main(args: Array[String]) { + val system = ActorSystem() + system.actorOf[HelloActor] ! Start + } +} + +class HelloActor extends Actor { + val worldActor = system.actorOf[WorldActor] + def receive = { + case Start ⇒ worldActor ! "Hello" + case s: String ⇒ + println("Received message: %s".format(s)) + system.stop() + } +} + +class WorldActor extends Actor { + def receive = { + case s: String ⇒ sender ! s.toUpperCase + " world!" + } +} + diff --git a/akka-samples/akka-sample-osgi/src/main/scala/OsgiExample.scala b/akka-samples/akka-sample-osgi/src/main/scala/OsgiExample.scala index 3e2d7af049..bf257ffd49 100644 --- a/akka-samples/akka-sample-osgi/src/main/scala/OsgiExample.scala +++ b/akka-samples/akka-sample-osgi/src/main/scala/OsgiExample.scala @@ -3,29 +3,27 @@ */ package sample.osgi -import akka.actor.Actor -import akka.actor.Actor._ - import org.osgi.framework.{ BundleActivator, BundleContext } +import akka.actor.{ Timeout, ActorSystem, Actor } class Activator extends BundleActivator { + val system = ActorSystem() def start(context: BundleContext) { println("Starting the OSGi example ...") - val echo = actorOf[EchoActor] - val answer = (echo ? "OSGi example").as[String] + val echo = system.actorOf[EchoActor] + val answer = (echo ? ("OSGi example", Timeout(100))).as[String] println(answer getOrElse "No answer!") } def stop(context: BundleContext) { - Actor.registry.local.shutdownAll() + system.stop() println("Stopped the OSGi example.") } } class EchoActor extends Actor { - override def receive = { - case x => reply(x) + case x ⇒ sender ! x } } diff --git a/akka-samples/akka-sample-remote/src/main/scala/ServerManagedRemoteActorSample.scala b/akka-samples/akka-sample-remote/src/main/scala/ServerManagedRemoteActorSample.scala index 84a201f530..9b3a27a7ae 100644 --- a/akka-samples/akka-sample-remote/src/main/scala/ServerManagedRemoteActorSample.scala +++ b/akka-samples/akka-sample-remote/src/main/scala/ServerManagedRemoteActorSample.scala @@ -2,35 +2,37 @@ * Copyright (C) 2009-2011 Typesafe Inc. */ -package sample.remote - -import akka.actor.Actor._ -import akka.actor. {ActorRegistry, Actor} - -class HelloWorldActor extends Actor { - def receive = { - case "Hello" => - reply("World") - } -} - -object ServerManagedRemoteActorServer { - - def run = { - Actor.remote.start("localhost", 2552) - Actor.remote.register("hello-service", actorOf[HelloWorldActor]) - } - - def main(args: Array[String]) = run -} - -object ServerManagedRemoteActorClient { - - def run = { - val actor = Actor.remote.actorFor("hello-service", "localhost", 2552) - val result = actor !! "Hello" - } - - def main(args: Array[String]) = run -} +// REMOTING IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +//package sample.remote +// +//import akka.actor.Actor._ +//import akka.actor. {ActorRegistry, Actor} +// +//class HelloWorldActor extends Actor { +// def receive = { +// case "Hello" => +// reply("World") +// } +//} +// +//object ServerManagedRemoteActorServer { +// +// def run = { +// Actor.remote.start("localhost", 2552) +// Actor.remote.register("hello-service", actorOf[HelloWorldActor]) +// } +// +// def main(args: Array[String]) = run +//} +// +//object ServerManagedRemoteActorClient { +// +// def run = { +// val actor = Actor.remote.actorFor("hello-service", "localhost", 2552) +// val result = actor !! "Hello" +// } +// +// def main(args: Array[String]) = run +//} +// diff --git a/akka-tutorials/akka-tutorial-first/pom.xml b/akka-tutorials/akka-tutorial-first/pom.xml index 8e25d972f3..1cec835a9c 100644 --- a/akka-tutorials/akka-tutorial-first/pom.xml +++ b/akka-tutorials/akka-tutorial-first/pom.xml @@ -13,7 +13,7 @@ - se.scalablesolutions.akka + com.typesafe.akka akka-actor 2.0-SNAPSHOT diff --git a/akka-tutorials/akka-tutorial-first/project/TutorialBuild.scala b/akka-tutorials/akka-tutorial-first/project/TutorialBuild.scala new file mode 100644 index 0000000000..5e5ef32493 --- /dev/null +++ b/akka-tutorials/akka-tutorial-first/project/TutorialBuild.scala @@ -0,0 +1,22 @@ +import sbt._ +import Keys._ + +object TutorialBuild extends Build { + lazy val buildSettings = Seq( + organization := "com.typesafe.akka", + version := "2.0-SNAPSHOT", + scalaVersion := "2.9.1" + ) + + lazy val akka = Project( + id = "akka-tutorial-first", + base = file("."), + settings = Defaults.defaultSettings ++ Seq( + libraryDependencies ++= Seq( + "com.typesafe.akka" % "akka-actor" % "2.0-SNAPSHOT", + "junit" % "junit" % "4.5" % "test", + "org.scalatest" % "scalatest_2.9.0" % "1.6.1" % "test", + "com.typesafe.akka" % "akka-testkit" % "2.0-SNAPSHOT" % "test") + ) + ) +} \ No newline at end of file diff --git a/akka-tutorials/akka-tutorial-first/project/build.properties b/akka-tutorials/akka-tutorial-first/project/build.properties index 4981c1c2c3..c6158f7be4 100644 --- a/akka-tutorials/akka-tutorial-first/project/build.properties +++ b/akka-tutorials/akka-tutorial-first/project/build.properties @@ -1,5 +1 @@ -project.organization=se.scalablesolutions.akka -project.name=akka-tutorial-first -project.version=2.0-SNAPSHOT -build.scala.versions=2.9.0 -sbt.version=0.7.7 +sbt.version=0.11.0 \ No newline at end of file diff --git a/akka-tutorials/akka-tutorial-first/project/build/Project.scala b/akka-tutorials/akka-tutorial-first/project/build/Project.scala deleted file mode 100644 index 975f2ce970..0000000000 --- a/akka-tutorials/akka-tutorial-first/project/build/Project.scala +++ /dev/null @@ -1,3 +0,0 @@ -import sbt._ - -class TutorialOneProject(info: ProjectInfo) extends DefaultProject(info) with AkkaProject diff --git a/akka-tutorials/akka-tutorial-first/project/plugins/Plugins.scala b/akka-tutorials/akka-tutorial-first/project/plugins/Plugins.scala deleted file mode 100644 index fb121fcd3e..0000000000 --- a/akka-tutorials/akka-tutorial-first/project/plugins/Plugins.scala +++ /dev/null @@ -1,6 +0,0 @@ -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" % "2.0-SNAPSHOT" -} 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 ca8fe597f7..d6b9e8c1f1 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 @@ -1,182 +1,184 @@ -// * -// * Copyright (C) 2009-2011 Typesafe Inc. +/** + * Copyright (C) 2009-2011 Typesafe Inc. + */ +package akka.tutorial.first.java; -// package akka.tutorial.first.java; +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.UntypedActor; +import akka.actor.UntypedActorFactory; +import akka.japi.Creator; +import akka.routing.*; -// import static akka.actor.Actors.poisonPill; -// import static java.util.Arrays.asList; +import java.util.LinkedList; +import java.util.concurrent.CountDownLatch; -// import akka.actor.ActorRef; -// import akka.actor.Actors; -// import akka.actor.ActorSystem; -// import akka.actor.UntypedActor; -// import akka.actor.UntypedActorFactory; -// import akka.routing.RoutedProps; -// import akka.routing.RouterType; -// import akka.routing.LocalConnectionManager; -// import akka.routing.Routing; -// import akka.routing.Routing.Broadcast; -// import scala.collection.JavaConversions; +public class Pi { -// import java.util.LinkedList; -// import java.util.concurrent.CountDownLatch; + private static final ActorSystem system = ActorSystem.apply(); -// public class Pi { + public static void main(String[] args) throws Exception { + Pi pi = new Pi(); + pi.calculate(4, 10000, 10000); + } -// private static final ActorSystem system = new ActorSystem(); + // ==================== + // ===== Messages ===== + // ==================== + static class Calculate { + } -// public static void main(String[] args) throws Exception { -// Pi pi = new Pi(); -// pi.calculate(4, 10000, 10000); -// } + static class Work { + private final int start; + private final int nrOfElements; -// // ==================== -// // ===== Messages ===== -// // ==================== -// static class Calculate {} + public Work(int start, int nrOfElements) { + this.start = start; + this.nrOfElements = nrOfElements; + } -// static class Work { -// private final int start; -// private final int nrOfElements; + public int getStart() { + return start; + } -// public Work(int start, int nrOfElements) { -// this.start = start; -// this.nrOfElements = nrOfElements; -// } + public int getNrOfElements() { + return nrOfElements; + } + } -// public int getStart() { return start; } -// public int getNrOfElements() { return nrOfElements; } -// } + static class Result { + private final double value; -// static class Result { -// private final double value; + public Result(double value) { + this.value = value; + } -// public Result(double value) { -// this.value = value; -// } + public double getValue() { + return value; + } + } -// public double getValue() { return value; } -// } + // ================== + // ===== Worker ===== + // ================== + public static class Worker extends UntypedActor { -// // ================== -// // ===== Worker ===== -// // ================== -// static class Worker extends UntypedActor { + // define the work + private double calculatePiFor(int start, int nrOfElements) { + double acc = 0.0; + for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) { + acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1); + } + return acc; + } -// // define the work -// private double calculatePiFor(int start, int nrOfElements) { -// double acc = 0.0; -// for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) { -// acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1); -// } -// return acc; -// } + // message handler + public void onReceive(Object message) { + if (message instanceof Work) { + Work work = (Work) message; -// // message handler -// public void onReceive(Object message) { -// if (message instanceof Work) { -// Work work = (Work) message; + // perform the work + double result = calculatePiFor(work.getStart(), work.getNrOfElements()); -// // perform the work -// double result = calculatePiFor(work.getStart(), work.getNrOfElements()); + // reply with the result + getSender().tell(new Result(result)); -// // reply with the result -// getSender().tell(new Result(result)); + } else throw new IllegalArgumentException("Unknown message [" + message + "]"); + } + } -// } else throw new IllegalArgumentException("Unknown message [" + message + "]"); -// } -// } + // ================== + // ===== Master ===== + // ================== + public static class Master extends UntypedActor { + private final int nrOfMessages; + private final int nrOfElements; + private final CountDownLatch latch; -// // ================== -// // ===== Master ===== -// // ================== -// static class Master extends UntypedActor { -// private final int nrOfMessages; -// private final int nrOfElements; -// private final CountDownLatch latch; + private double pi; + private int nrOfResults; + private long start; -// private double pi; -// private int nrOfResults; -// private long start; + private ActorRef router; -// private ActorRef router; + public Master(final int nrOfWorkers, int nrOfMessages, int nrOfElements, CountDownLatch latch) { + this.nrOfMessages = nrOfMessages; + this.nrOfElements = nrOfElements; + this.latch = latch; + Creator routerCreator = new Creator() { + public Router create() { + return new RoundRobinRouter(); + } + }; + LinkedList actors = new LinkedList() { + { + for (int i = 0; i < nrOfWorkers; i++) add(system.actorOf(Worker.class)); + } + }; + RoutedProps props = new RoutedProps(routerCreator, new LocalConnectionManager(actors), new akka.actor.Timeout(-1), true); + router = new RoutedActorRef(system, props, getSelf(), "pi"); + } -// public Master(int nrOfWorkers, int nrOfMessages, int nrOfElements, CountDownLatch latch) { -// this.nrOfMessages = nrOfMessages; -// this.nrOfElements = nrOfElements; -// this.latch = latch; + // message handler + public void onReceive(Object message) { -// LinkedList workers = new LinkedList(); -// for (int i = 0; i < nrOfWorkers; i++) { -// ActorRef worker = system.actorOf(Worker.class); -// workers.add(worker); -// } + if (message instanceof Calculate) { -// router = system.actorOf(new RoutedProps().withRoundRobinRouter().withLocalConnections(workers), "pi"); -// } + // schedule work + for (int start = 0; start < nrOfMessages; start++) { + router.tell(new Work(start, nrOfElements), getSelf()); + } -// // message handler -// public void onReceive(Object message) { + } else if (message instanceof Result) { -// if (message instanceof Calculate) { -// // schedule work -// for (int start = 0; start < nrOfMessages; start++) { -// router.tell(new Work(start, nrOfElements), getSelf()); -// } + // handle result from the worker + Result result = (Result) message; + pi += result.getValue(); + nrOfResults += 1; + if (nrOfResults == nrOfMessages) getSelf().stop(); -// // send a PoisonPill to all workers telling them to shut down themselves -// router.tell(new Broadcast(poisonPill())); + } else throw new IllegalArgumentException("Unknown message [" + message + "]"); + } -// // send a PoisonPill to the router, telling him to shut himself down -// router.tell(poisonPill()); + @Override + public void preStart() { + start = System.currentTimeMillis(); + } -// } else if (message instanceof Result) { + @Override + public void postStop() { + // tell the world that the calculation is complete + System.out.println(String.format( + "\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis", + pi, (System.currentTimeMillis() - start))); + latch.countDown(); + } + } -// // handle result from the worker -// Result result = (Result) message; -// pi += result.getValue(); -// nrOfResults += 1; -// if (nrOfResults == nrOfMessages) getSelf().stop(); + // ================== + // ===== Run it ===== + // ================== + public void calculate(final int nrOfWorkers, final int nrOfElements, final int nrOfMessages) + throws Exception { -// } else throw new IllegalArgumentException("Unknown message [" + message + "]"); -// } + // this latch is only plumbing to know when the calculation is completed + final CountDownLatch latch = new CountDownLatch(1); -// @Override -// public void preStart() { -// start = System.currentTimeMillis(); -// } + // create the master + ActorRef master = system.actorOf(new UntypedActorFactory() { + public UntypedActor create() { + return new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch); + } + }); -// @Override -// public void postStop() { -// // tell the world that the calculation is complete -// System.out.println(String.format( -// "\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis", -// pi, (System.currentTimeMillis() - start))); -// latch.countDown(); -// } -// } + // start the calculation + master.tell(new Calculate()); -// // ================== -// // ===== Run it ===== -// // ================== -// public void calculate(final int nrOfWorkers, final int nrOfElements, final int nrOfMessages) -// throws Exception { + // wait for master to shut down + latch.await(); -// // this latch is only plumbing to know when the calculation is completed -// final CountDownLatch latch = new CountDownLatch(1); - -// // create the master -// ActorRef master = system.actorOf(new UntypedActorFactory() { -// public UntypedActor create() { -// return new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch); -// } -// }); - -// // start the calculation -// master.tell(new Calculate()); - -// // wait for master to shut down -// latch.await(); -// } -// } + // Shut down the system + system.stop(); + } +} 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 836f766e12..d7f932a053 100644 --- a/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala +++ b/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala @@ -1,113 +1,114 @@ -// /** -// * Copyright (C) 2009-2011 Typesafe Inc. -// */ +/** + * Copyright (C) 2009-2011 Typesafe Inc. + */ +package akka.tutorial.first.scala -// package akka.tutorial.first.scala +import java.util.concurrent.CountDownLatch +import akka.routing.{ RoutedActorRef, LocalConnectionManager, RoundRobinRouter, RoutedProps } +import akka.actor.{ ActorSystemImpl, Actor, ActorSystem } -// import akka.actor.{ Actor, PoisonPill, ActorSystem } -// import Actor._ -// import java.util.concurrent.CountDownLatch -// import akka.routing.Routing.Broadcast -// import akka.routing.{ RoutedProps, Routing } +object Pi extends App { -// object Pi extends App { + val system = ActorSystem() -// val system = ActorSystem() + // Initiate the calculation + calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000) -// calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000) + // ==================== + // ===== Messages ===== + // ==================== + sealed trait PiMessage -// // ==================== -// // ===== Messages ===== -// // ==================== -// sealed trait PiMessage + case object Calculate extends PiMessage -// case object Calculate extends PiMessage + case class Work(start: Int, nrOfElements: Int) extends PiMessage -// case class Work(start: Int, nrOfElements: Int) extends PiMessage + case class Result(value: Double) extends PiMessage -// case class Result(value: Double) extends PiMessage + // ================== + // ===== Worker ===== + // ================== + class Worker extends Actor { -// // ================== -// // ===== Worker ===== -// // ================== -// class Worker extends Actor { + // define the work + def calculatePiFor(start: Int, nrOfElements: Int): Double = { + var acc = 0.0 + for (i ← start until (start + nrOfElements)) + acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1) + acc + } -// // define the work -// def calculatePiFor(start: Int, nrOfElements: Int): Double = { -// var acc = 0.0 -// for (i ← start until (start + nrOfElements)) -// acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1) -// acc -// } + def receive = { + case Work(start, nrOfElements) ⇒ sender ! Result(calculatePiFor(start, nrOfElements)) // perform the work + } + } -// def receive = { -// case Work(start, nrOfElements) ⇒ sender ! Result(calculatePiFor(start, nrOfElements)) // perform the work -// } -// } + // ================== + // ===== Master ===== + // ================== + class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch) + extends Actor { -// // ================== -// // ===== Master ===== -// // ================== -// class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch) -// extends Actor { + var pi: Double = _ + var nrOfResults: Int = _ + var start: Long = _ -// var pi: Double = _ -// var nrOfResults: Int = _ -// var start: Long = _ + // create the workers + val workers = Vector.fill(nrOfWorkers)(system.actorOf[Worker]) -// // create the workers -// val workers = Vector.fill(nrOfWorkers)(system.actorOf[Worker]) + // wrap them with a load-balancing router + val props = RoutedProps(routerFactory = () ⇒ new RoundRobinRouter, connectionManager = new LocalConnectionManager(workers)) + val router = new RoutedActorRef(system, props, self, "pi") -// // wrap them with a load-balancing router -// val router = system.actorOf(RoutedProps().withRoundRobinRouter.withLocalConnections(workers), "pi") + // message handler + def receive = { + case Calculate ⇒ + // schedule work + for (i ← 0 until nrOfMessages) router ! Work(i * nrOfElements, nrOfElements) + case Result(value) ⇒ + // handle result from the worker + pi += value + nrOfResults += 1 -// // message handler -// def receive = { -// case Calculate ⇒ -// // schedule work -// for (i ← 0 until nrOfMessages) router ! Work(i * nrOfElements, nrOfElements) + // Stop this actor and all its supervised children + if (nrOfResults == nrOfMessages) self.stop() + } -// // send a PoisonPill to all workers telling them to shut down themselves -// router ! Broadcast(PoisonPill) + override def preStart() { + start = System.currentTimeMillis + } -// // send a PoisonPill to the router, telling him to shut himself down -// router ! PoisonPill + override def postStop() { + // tell the world that the calculation is complete + println( + "\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis" + .format(pi, (System.currentTimeMillis - start))) + latch.countDown() + } + } -// case Result(value) ⇒ -// // handle result from the worker -// pi += value -// nrOfResults += 1 -// if (nrOfResults == nrOfMessages) self.stop() -// } + object Master { + val impl = system.asInstanceOf[ActorSystemImpl] + } -// override def preStart() { -// start = System.currentTimeMillis -// } + // ================== + // ===== Run it ===== + // ================== + def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) { -// override def postStop() { -// // tell the world that the calculation is complete -// println( -// "\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis" -// .format(pi, (System.currentTimeMillis - start))) -// latch.countDown() -// } -// } + // this latch is only plumbing to know when the calculation is completed + val latch = new CountDownLatch(1) -// // ================== -// // ===== Run it ===== -// // ================== -// def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) { + // create the master + val master = system.actorOf(new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch)) -// // this latch is only plumbing to know when the calculation is completed -// val latch = new CountDownLatch(1) + // start the calculation + master ! Calculate -// // create the master -// val master = system.actorOf(new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch)) + // wait for master to shut down + latch.await() -// // start the calculation -// master ! Calculate - -// // wait for master to shut down -// latch.await() -// } -// } + // Shut down the system + system.stop() + } +} diff --git a/akka-tutorials/akka-tutorial-first/src/test/scala/WorkerSpec.scala b/akka-tutorials/akka-tutorial-first/src/test/scala/WorkerSpec.scala new file mode 100644 index 0000000000..608ba55481 --- /dev/null +++ b/akka-tutorials/akka-tutorial-first/src/test/scala/WorkerSpec.scala @@ -0,0 +1,26 @@ +/** + * Copyright (C) 2009-2011 Typesafe Inc. + */ +package akka.tutorial.first.scala + +import org.junit.runner.RunWith +import org.scalatest.matchers.MustMatchers +import org.scalatest.WordSpec +import akka.testkit.TestActorRef +import akka.tutorial.first.scala.Pi.Worker +import akka.actor.ActorSystem + +@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) +class WorkerSpec extends WordSpec with MustMatchers { + + implicit def system = ActorSystem() + + "Worker" must { + "calculate pi correctly" in { + val testActor = TestActorRef[Worker] + val actor = testActor.underlyingActor + actor.calculatePiFor(0, 0) must equal(0.0) + actor.calculatePiFor(1, 1) must equal(-1.3333333333333333) + } + } +} \ No newline at end of file diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index dd09fe3c80..e4fb06a8cc 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -243,23 +243,31 @@ object AkkaBuild extends Build { id = "akka-samples", base = file("akka-samples"), settings = parentSettings, - aggregate = Seq(fsmSample) - // aggregate = Seq(fsmSample, camelSample) + aggregate = Seq(antsSample, helloSample, osgiSample, fsmSample) ) - // lazy val antsSample = Project( - // id = "akka-sample-ants", - // base = file("akka-samples/akka-sample-ants"), - // dependencies = Seq(stm), - // settings = defaultSettings - // ) + lazy val antsSample = Project( + id = "akka-sample-ants", + base = file("akka-samples/akka-sample-ants"), + dependencies = Seq(actor, stm), + settings = defaultSettings + ) - // lazy val chatSample = Project( - // id = "akka-sample-chat", - // base = file("akka-samples/akka-sample-chat"), - // dependencies = Seq(cluster), - // settings = defaultSettings - // ) + lazy val helloSample = Project( + id = "akka-sample-hello", + base = file("akka-samples/akka-sample-hello"), + dependencies = Seq(actor), + settings = defaultSettings + ) + + lazy val osgiSample = Project( + id = "akka-sample-osgi", + base = file("akka-samples/akka-sample-osgi"), + dependencies = Seq(actor), + settings = defaultSettings ++ Seq( + libraryDependencies ++= Dependencies.sampleOsgi + ) + ) lazy val fsmSample = Project( id = "akka-sample-fsm", @@ -268,6 +276,21 @@ object AkkaBuild extends Build { settings = defaultSettings ) + // lazy val chatSample = Project( + // id = "akka-sample-chat", + // base = file("akka-samples/akka-sample-chat"), + // dependencies = Seq(cluster), + // settings = defaultSettings + // ) + + // lazy val samples = Project( + // id = "akka-samples", + // base = file("akka-samples"), + // settings = parentSettings, + // aggregate = Seq(fsmSample) + // // aggregate = Seq(fsmSample, camelSample) + // ) + // lazy val camelSample = Project( // id = "akka-sample-camel", // base = file("akka-samples/akka-sample-camel"), @@ -277,13 +300,6 @@ object AkkaBuild extends Build { // ) // ) - // lazy val helloSample = Project( - // id = "akka-sample-hello", - // base = file("akka-samples/akka-sample-hello"), - // dependencies = Seq(kernel), - // settings = defaultSettings - // ) - // lazy val remoteSample = Project( // id = "akka-sample-remote", // base = file("akka-samples/akka-sample-remote"), @@ -295,22 +311,24 @@ object AkkaBuild extends Build { id = "akka-tutorials", base = file("akka-tutorials"), settings = parentSettings, - aggregate = Seq(firstTutorial, secondTutorial) + aggregate = Seq(firstTutorial) ) lazy val firstTutorial = Project( id = "akka-tutorial-first", base = file("akka-tutorials/akka-tutorial-first"), - dependencies = Seq(actor), - settings = defaultSettings + dependencies = Seq(actor, testkit), + settings = defaultSettings ++ Seq( + libraryDependencies ++= Dependencies.tutorials + ) ) - lazy val secondTutorial = Project( - id = "akka-tutorial-second", - base = file("akka-tutorials/akka-tutorial-second"), - dependencies = Seq(actor), - settings = defaultSettings - ) + // lazy val secondTutorial = Project( + // id = "akka-tutorial-second", + // base = file("akka-tutorials/akka-tutorial-second"), + // dependencies = Seq(actor), + // settings = defaultSettings + // ) lazy val docs = Project( id = "akka-docs", @@ -448,6 +466,10 @@ object Dependencies { // val sampleCamel = Seq(camelCore, camelSpring, commonsCodec, Runtime.camelJms, Runtime.activemq, Runtime.springJms, // Test.junit, Test.scalatest, Test.logback) + val sampleOsgi = Seq(osgi) + + val tutorials = Seq(Test.scalatest, Test.junit) + val docs = Seq(Test.scalatest, Test.junit) } From c1f9e764a946aee5322751fb4ec4cdfd5af44eae Mon Sep 17 00:00:00 2001 From: Henrik Engstrom Date: Tue, 29 Nov 2011 12:41:52 +0100 Subject: [PATCH 05/23] Replaced removed visibility, see #1278 --- akka-actor/src/main/scala/akka/routing/Routing.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/akka-actor/src/main/scala/akka/routing/Routing.scala b/akka-actor/src/main/scala/akka/routing/Routing.scala index 8257002a42..424321e2c0 100644 --- a/akka-actor/src/main/scala/akka/routing/Routing.scala +++ b/akka-actor/src/main/scala/akka/routing/Routing.scala @@ -174,7 +174,7 @@ abstract private[akka] class AbstractRoutedActorRef(val system: ActorSystem, val * A RoutedActorRef is an ActorRef that has a set of connected ActorRef and it uses a Router to send a message to * on (or more) of these actors. */ -class RoutedActorRef(system: ActorSystem, val routedProps: RoutedProps, val supervisor: ActorRef, override val name: String) extends AbstractRoutedActorRef(system, routedProps) { +private[akka] class RoutedActorRef(system: ActorSystem, val routedProps: RoutedProps, val supervisor: ActorRef, override val name: String) extends AbstractRoutedActorRef(system, routedProps) { val path = supervisor.path / name From 1b3ee0828736bc6e4a96c39517efa2c736eda0f5 Mon Sep 17 00:00:00 2001 From: Henrik Engstrom Date: Tue, 29 Nov 2011 15:19:58 +0100 Subject: [PATCH 06/23] Updated after comments, see #1278 --- akka-samples/akka-sample-ants/README.md | 2 -- akka-samples/akka-sample-fsm/src/README | 2 -- .../src/main/scala/DiningHakkersOnBecome.scala | 2 +- .../src/main/scala/DiningHakkersOnFsm.scala | 2 +- akka-samples/akka-sample-hello/src/README | 2 -- .../src/main/scala/sample/hello/Main.scala | 2 +- .../src/main/java/akka/tutorial/first/java/Pi.java | 8 +++----- .../akka-tutorial-first/src/main/scala/Pi.scala | 7 +------ .../akka-tutorial-first/src/test/scala/WorkerSpec.scala | 2 +- 9 files changed, 8 insertions(+), 21 deletions(-) diff --git a/akka-samples/akka-sample-ants/README.md b/akka-samples/akka-sample-ants/README.md index 5a416e0ba4..2eaced5663 100644 --- a/akka-samples/akka-sample-ants/README.md +++ b/akka-samples/akka-sample-ants/README.md @@ -19,8 +19,6 @@ Here is an example. First type 'sbt' to start SBT interactively, the run 'update > % sbt -> > update - > > project akka-sample-ants > > run diff --git a/akka-samples/akka-sample-fsm/src/README b/akka-samples/akka-sample-fsm/src/README index 17971c005b..1391071f0b 100644 --- a/akka-samples/akka-sample-fsm/src/README +++ b/akka-samples/akka-sample-fsm/src/README @@ -15,8 +15,6 @@ Here is an example. First type 'sbt' to start SBT interactively, the run 'update > % sbt -> > update - > > project akka-sample-fsm > > run diff --git a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala index 3acbf473e6..78449edc1b 100644 --- a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala +++ b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala @@ -127,7 +127,7 @@ class Hakker(name: String, left: ActorRef, right: ActorRef) extends Actor { object DiningHakkers { val system = ActorSystem() - def main(args: Array[String]) { + def main(args: Array[String]): Unit = { run } diff --git a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala index d0c8bca54a..b9cea1fe8f 100644 --- a/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala +++ b/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnFsm.scala @@ -168,7 +168,7 @@ object DiningHakkersOnFsm { val system = ActorSystem() - def main(args: Array[String]) { + def main(args: Array[String]): Unit = { run } diff --git a/akka-samples/akka-sample-hello/src/README b/akka-samples/akka-sample-hello/src/README index cd271f1dde..81a6db8d3e 100644 --- a/akka-samples/akka-sample-hello/src/README +++ b/akka-samples/akka-sample-hello/src/README @@ -15,8 +15,6 @@ Here is an example. First type 'sbt' to start SBT interactively, the run 'update > % sbt -> > update - > > project akka-sample-hello > > run diff --git a/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Main.scala b/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Main.scala index e3399e86fc..5df2661800 100644 --- a/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Main.scala +++ b/akka-samples/akka-sample-hello/src/main/scala/sample/hello/Main.scala @@ -8,7 +8,7 @@ import akka.actor.{ ActorSystem, Actor } case object Start object Main { - def main(args: Array[String]) { + def main(args: Array[String]): Unit = { val system = ActorSystem() system.actorOf[HelloActor] ! Start } 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 d6b9e8c1f1..c8e9d88121 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 @@ -16,8 +16,6 @@ import java.util.concurrent.CountDownLatch; public class Pi { - private static final ActorSystem system = ActorSystem.apply(); - public static void main(String[] args) throws Exception { Pi pi = new Pi(); pi.calculate(4, 10000, 10000); @@ -113,18 +111,17 @@ public class Pi { }; LinkedList actors = new LinkedList() { { - for (int i = 0; i < nrOfWorkers; i++) add(system.actorOf(Worker.class)); + for (int i = 0; i < nrOfWorkers; i++) add(context().actorOf(Worker.class)); } }; RoutedProps props = new RoutedProps(routerCreator, new LocalConnectionManager(actors), new akka.actor.Timeout(-1), true); - router = new RoutedActorRef(system, props, getSelf(), "pi"); + router = new RoutedActorRef(system(), props, getSelf(), "pi"); } // message handler public void onReceive(Object message) { if (message instanceof Calculate) { - // schedule work for (int start = 0; start < nrOfMessages; start++) { router.tell(new Work(start, nrOfElements), getSelf()); @@ -161,6 +158,7 @@ public class Pi { // ================== public void calculate(final int nrOfWorkers, final int nrOfElements, final int nrOfMessages) throws Exception { + final ActorSystem system = ActorSystem.create(); // this latch is only plumbing to know when the calculation is completed final CountDownLatch latch = new CountDownLatch(1); 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 d7f932a053..3283a591f4 100644 --- a/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala +++ b/akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala @@ -9,8 +9,6 @@ import akka.actor.{ ActorSystemImpl, Actor, ActorSystem } object Pi extends App { - val system = ActorSystem() - // Initiate the calculation calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000) @@ -87,14 +85,11 @@ object Pi extends App { } } - object Master { - val impl = system.asInstanceOf[ActorSystemImpl] - } - // ================== // ===== Run it ===== // ================== def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) { + val system = ActorSystem() // this latch is only plumbing to know when the calculation is completed val latch = new CountDownLatch(1) diff --git a/akka-tutorials/akka-tutorial-first/src/test/scala/WorkerSpec.scala b/akka-tutorials/akka-tutorial-first/src/test/scala/WorkerSpec.scala index 608ba55481..de5851bfe7 100644 --- a/akka-tutorials/akka-tutorial-first/src/test/scala/WorkerSpec.scala +++ b/akka-tutorials/akka-tutorial-first/src/test/scala/WorkerSpec.scala @@ -20,7 +20,7 @@ class WorkerSpec extends WordSpec with MustMatchers { val testActor = TestActorRef[Worker] val actor = testActor.underlyingActor actor.calculatePiFor(0, 0) must equal(0.0) - actor.calculatePiFor(1, 1) must equal(-1.3333333333333333) + actor.calculatePiFor(1, 1) must be(-1.3333333333333333 plusOrMinus 0.0000000001) } } } \ No newline at end of file From 8f5ddff153ce0a2eb50d1b2756a8f6e3abb2ee24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bone=CC=81r?= Date: Tue, 29 Nov 2011 16:40:39 +0100 Subject: [PATCH 07/23] Added initial support for ls.implicit.ly to the build, still need more work though --- build.sbt | 7 +++++++ project/plugins.sbt | 6 ++++++ 2 files changed, 13 insertions(+) create mode 100644 build.sbt diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000000..13467e1654 --- /dev/null +++ b/build.sbt @@ -0,0 +1,7 @@ + seq(lsSettings:_*) + + (LsKeys.tags in LsKeys.lsync) := Seq("actors", "stm", "concurrency", "distributed", "fault-tolerance", "scala", "java", "futures", "dataflow", "remoting") + + (externalResolvers in LsKeys.lsync) := Seq("Akka Repository" at "http://akka.io/repository/") + + (description in LsKeys.lsync) := "Akka is the platform for the next generation of event-driven, scalable and fault-tolerant architectures on the JVM." diff --git a/project/plugins.sbt b/project/plugins.sbt index 8b6d17a0c3..7140718543 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,3 +4,9 @@ resolvers += Classpaths.typesafeResolver addSbtPlugin("com.typesafe.sbtmultijvm" % "sbt-multi-jvm" % "0.1.7") addSbtPlugin("com.typesafe.sbtscalariform" % "sbt-scalariform" % "0.1.4") + +resolvers ++= Seq( + "less is" at "http://repo.lessis.me", + "coda" at "http://repo.codahale.com") + +addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.0") From 9afc9dc768ac5c95735ea5663b2846029ae0bcee Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 29 Nov 2011 16:51:30 +0100 Subject: [PATCH 08/23] Making sure that all access to status and systemMessage is through Unsafe --- .../src/main/java/akka/dispatch/AbstractMailbox.java | 4 ++-- .../src/main/scala/akka/dispatch/Mailbox.scala | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/akka-actor/src/main/java/akka/dispatch/AbstractMailbox.java b/akka-actor/src/main/java/akka/dispatch/AbstractMailbox.java index 80cc4c9675..dbe87482dc 100644 --- a/akka-actor/src/main/java/akka/dispatch/AbstractMailbox.java +++ b/akka-actor/src/main/java/akka/dispatch/AbstractMailbox.java @@ -12,8 +12,8 @@ final class AbstractMailbox { static { try { - mailboxStatusOffset = Unsafe.instance.objectFieldOffset(Mailbox.class.getDeclaredField("_status")); - systemMessageOffset = Unsafe.instance.objectFieldOffset(Mailbox.class.getDeclaredField("_systemQueue")); + mailboxStatusOffset = Unsafe.instance.objectFieldOffset(Mailbox.class.getDeclaredField("_statusDoNotCallMeDirectly")); + systemMessageOffset = Unsafe.instance.objectFieldOffset(Mailbox.class.getDeclaredField("_systemQueueDoNotCallMeDirectly")); } catch(Throwable t){ throw new ExceptionInInitializerError(t); } diff --git a/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala b/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala index 7d3b3c3d8b..49110c2974 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala @@ -40,13 +40,13 @@ abstract class Mailbox(val actor: ActorCell) extends MessageQueue with SystemMes import Mailbox._ @volatile - protected var _status: Status = _ //0 by default + protected var _statusDoNotCallMeDirectly: Status = _ //0 by default @volatile - protected var _systemQueue: SystemMessage = _ //null by default + protected var _systemQueueDoNotCallMeDirectly: SystemMessage = _ //null by default @inline - final def status: Mailbox.Status = _status + final def status: Mailbox.Status = Unsafe.instance.getIntVolatile(this, AbstractMailbox.mailboxStatusOffset) @inline final def shouldProcessMessage: Boolean = (status & 3) == Open @@ -65,7 +65,8 @@ abstract class Mailbox(val actor: ActorCell) extends MessageQueue with SystemMes Unsafe.instance.compareAndSwapInt(this, AbstractMailbox.mailboxStatusOffset, oldStatus, newStatus) @inline - protected final def setStatus(newStatus: Status): Unit = _status = newStatus + protected final def setStatus(newStatus: Status): Unit = + Unsafe.instance.putIntVolatile(this, AbstractMailbox.mailboxStatusOffset, newStatus) /** * set new primary status Open. Caller does not need to worry about whether @@ -130,7 +131,8 @@ abstract class Mailbox(val actor: ActorCell) extends MessageQueue with SystemMes /* * AtomicReferenceFieldUpdater for system queue */ - protected final def systemQueueGet: SystemMessage = _systemQueue + protected final def systemQueueGet: SystemMessage = + Unsafe.instance.getObjectVolatile(this, AbstractMailbox.systemMessageOffset).asInstanceOf[SystemMessage] protected final def systemQueuePut(_old: SystemMessage, _new: SystemMessage): Boolean = Unsafe.instance.compareAndSwapObject(this, AbstractMailbox.systemMessageOffset, _old, _new) From 5cc36fa4765db966dc216a4b02615d15a0407f06 Mon Sep 17 00:00:00 2001 From: Henrik Engstrom Date: Tue, 29 Nov 2011 17:12:57 +0100 Subject: [PATCH 09/23] Added todos for 2.0 release, see #1278 --- .../akka-sample-camel/src/main/scala/sample/camel/Actors.scala | 1 + .../akka-sample-camel/src/main/scala/sample/camel/Boot.scala | 1 + .../src/main/scala/sample/camel/ClientApplication.scala | 1 + .../src/main/scala/sample/camel/ServerApplication.scala | 1 + .../src/main/scala/sample/camel/StandaloneApplication.scala | 1 + akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala | 1 + .../src/main/scala/ServerManagedRemoteActorSample.scala | 1 + 7 files changed, 7 insertions(+) diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Actors.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Actors.scala index c091d7dfd8..05252fe308 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Actors.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Actors.scala @@ -3,6 +3,7 @@ */ // CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +// TODO FIXME 2.0 //package sample.camel // diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala index 31b76835a4..845141b4fc 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala @@ -3,6 +3,7 @@ */ // CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +// TODO FIXME 2.0 //package sample.camel // diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ClientApplication.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ClientApplication.scala index a4c5edf398..a5bbce4919 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ClientApplication.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ClientApplication.scala @@ -3,6 +3,7 @@ */ // CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +// TODO FIXME 2.0 //package sample.camel // diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ServerApplication.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ServerApplication.scala index 1181e661d4..c852e0d167 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ServerApplication.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/ServerApplication.scala @@ -3,6 +3,7 @@ */ // CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +// TODO FIXME 2.0 //package sample.camel // diff --git a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/StandaloneApplication.scala b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/StandaloneApplication.scala index c87e6bdcab..9c995a95ef 100644 --- a/akka-samples/akka-sample-camel/src/main/scala/sample/camel/StandaloneApplication.scala +++ b/akka-samples/akka-sample-camel/src/main/scala/sample/camel/StandaloneApplication.scala @@ -3,6 +3,7 @@ */ // CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +// TODO FIXME 2.0 //package sample.camel // 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 49b5da2138..80cf2f7ab0 100644 --- a/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala +++ b/akka-samples/akka-sample-chat/src/main/scala/ChatServer.scala @@ -3,6 +3,7 @@ */ // REMOTING IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +// TODO FIXME 2.0 // // package sample.chat diff --git a/akka-samples/akka-sample-remote/src/main/scala/ServerManagedRemoteActorSample.scala b/akka-samples/akka-sample-remote/src/main/scala/ServerManagedRemoteActorSample.scala index 9b3a27a7ae..abfb148a89 100644 --- a/akka-samples/akka-sample-remote/src/main/scala/ServerManagedRemoteActorSample.scala +++ b/akka-samples/akka-sample-remote/src/main/scala/ServerManagedRemoteActorSample.scala @@ -3,6 +3,7 @@ */ // REMOTING IS NOT PART OF MILESTONE 1 OF AKKA 2.0 +// TODO FIXME 2.0 //package sample.remote // From 9e5c2f15fd3f80faa16cdcf232d46ddd5fbafae9 Mon Sep 17 00:00:00 2001 From: Henrik Engstrom Date: Wed, 30 Nov 2011 08:35:40 +0100 Subject: [PATCH 10/23] Changed LinkedList to Iterable in constructor, see #1278 --- .../src/main/scala/akka/routing/ConnectionManager.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala b/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala index e8649dc3db..6e45a50cad 100644 --- a/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala +++ b/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala @@ -86,8 +86,8 @@ trait ConnectionManager { */ class LocalConnectionManager(initialConnections: Iterable[ActorRef]) extends ConnectionManager { - def this(linkedList: java.util.LinkedList[ActorRef]) { - this(JavaConverters.iterableAsScalaIterableConverter(linkedList).asScala) + def this(iterable: java.lang.Iterable[ActorRef]) { + this(JavaConverters.iterableAsScalaIterableConverter(iterable).asScala) } case class State(version: Long, connections: Iterable[ActorRef]) extends VersionedIterable[ActorRef] { From 070d44616541a02c341e5bcefd367a9fdf10c6f3 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Wed, 30 Nov 2011 10:52:51 +0100 Subject: [PATCH 11/23] #1417 - Added a test to attempt to statistically verify memory consistency for actors --- .../scala/akka/actor/ConsistencySpec.scala | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala diff --git a/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala new file mode 100644 index 0000000000..c04e193c2b --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala @@ -0,0 +1,49 @@ +package akka.actor + +import akka.testkit.AkkaSpec +import akka.dispatch.UnboundedMailbox +import akka.util.duration._ + +object ConsistencySpec { + class CacheMisaligned(var value: Long, var padding1: Long, var padding2: Long, var padding3: Int) //Vars, no final fences + + class ConsistencyCheckingActor extends Actor { + var left = new CacheMisaligned(42, 0, 0, 0) //var + var right = new CacheMisaligned(0, 0, 0, 0) //var + def receive = { + case "check" ⇒ + var shouldBeFortyTwo = left.value + right.value + if (shouldBeFortyTwo != 42) + sender ! "Test failed" + else { + left.value += 1 + right.value -= 1 + } + case "done" ⇒ sender ! "done"; self.stop() + } + } +} + +class ConsistencySpec extends AkkaSpec { + import ConsistencySpec._ + "The Akka actor model implementation" must { + "provide memory consistency" in { + val dispatcher = system + .dispatcherFactory + .newDispatcher("consistency-dispatcher", 1, UnboundedMailbox()) + .withNewThreadPoolWithArrayBlockingQueueWithCapacityAndFairness(1000, true) + .setCorePoolSize(10) + .setMaxPoolSize(10) + .setKeepAliveTimeInMillis(1) + .setAllowCoreThreadTimeout(true) + .build + + val props = Props[ConsistencyCheckingActor].withDispatcher(dispatcher) + val actors = Vector.fill(3)(system.actorOf(props)) + for (i ← 1 to 1000000) actors(i % actors.size).tell("check", testActor) + for (a ← actors) a.tell("done", testActor) + + for (a ← actors) expectMsg(5 minutes, "done") + } + } +} \ No newline at end of file From 99e5d88ace3466ba75a8a2e906463f4549058cd0 Mon Sep 17 00:00:00 2001 From: Henrik Engstrom Date: Wed, 30 Nov 2011 11:37:42 +0100 Subject: [PATCH 12/23] Removed obsolete samples, see #1278 --- akka-samples/akka-sample-ants/README.md | 44 ---- .../src/main/scala/Ants.scala | 222 ------------------ akka-samples/akka-sample-fsm/{src => }/README | 0 .../akka-sample-hello/{src => }/README | 0 .../src/main/scala/OsgiExample.scala | 29 --- project/AkkaBuild.scala | 2 - 6 files changed, 297 deletions(-) delete mode 100644 akka-samples/akka-sample-ants/README.md delete mode 100644 akka-samples/akka-sample-ants/src/main/scala/Ants.scala rename akka-samples/akka-sample-fsm/{src => }/README (100%) rename akka-samples/akka-sample-hello/{src => }/README (100%) delete mode 100644 akka-samples/akka-sample-osgi/src/main/scala/OsgiExample.scala diff --git a/akka-samples/akka-sample-ants/README.md b/akka-samples/akka-sample-ants/README.md deleted file mode 100644 index 2eaced5663..0000000000 --- a/akka-samples/akka-sample-ants/README.md +++ /dev/null @@ -1,44 +0,0 @@ -Ants -==== - -Ants is written by Peter Vlugter. - -Ants is roughly based on the Clojure [ants simulation][ants.clj] by Rich Hickey, and ported to Scala using [Akka][akka] and [Spde][spde]. - -Requirements ------------- - -To build and run Ants you need [Simple Build Tool][sbt] (sbt). - -Running -------- - -First time, 'sbt update' to get dependencies, then to run Ants use 'sbt run'. -Here is an example. First type 'sbt' to start SBT interactively, the run 'update' and 'run': -> cd $AKKA_HOME - -> % sbt - -> > project akka-sample-ants - -> > run - - -Notice ------- - -Ants is roughly based on the Clojure ants simulation by Rich Hickey. - -Copyright (c) Rich Hickey. All rights reserved. -The use and distribution terms for this software are covered by the -Common Public License 1.0 ([http://opensource.org/licenses/cpl1.0.php][cpl]) -which can be found in the file cpl.txt at the root of this distribution. -By using this software in any fashion, you are agreeing to be bound by -the terms of this license. -You must not remove this notice, or any other, from this software. - -[ants.clj]: http://clojure.googlegroups.com/web/ants.clj -[akka]: http://akka.io -[spde]: http://technically.us/spde/ -[sbt]: http://code.google.com/p/simple-build-tool/ -[cpl]: http://opensource.org/licenses/cpl1.0.php \ No newline at end of file diff --git a/akka-samples/akka-sample-ants/src/main/scala/Ants.scala b/akka-samples/akka-sample-ants/src/main/scala/Ants.scala deleted file mode 100644 index 4b9cd8dd88..0000000000 --- a/akka-samples/akka-sample-ants/src/main/scala/Ants.scala +++ /dev/null @@ -1,222 +0,0 @@ -/** - * Copyright (C) 2009-2011 Typesafe Inc. - */ - -package sample.ants - -import scala.util.Random.{ nextInt ⇒ randomInt } -import akka.actor.{ ActorSystem, Actor, ActorRef } -import akka.util.Duration -import akka.util.duration._ -import java.util.concurrent.TimeUnit -import akka.stm._ - -object Config { - val Dim = 80 // dimensions of square world - val AntsSqrt = 20 // number of ants = AntsSqrt^2 - val FoodPlaces = 35 // number of places with food - val FoodRange = 100 // range of amount of food at a place - val PherScale = 10 // scale factor for pheromone drawing - val AntMillis = 100 // how often an ant behaves (milliseconds) - val EvapMillis = 1000 // how often pheromone evaporation occurs (milliseconds) - val EvapRate = 0.99f // pheromone evaporation rate - val StartDelay = 1000 milliseconds // delay before everything kicks off (milliseconds) -} - -case class Ant(dir: Int, food: Boolean = false) { - def turn(i: Int) = copy(dir = Util.dirBound(dir + i)) - def turnAround = turn(4) - def pickUp = copy(food = true) - def dropOff = copy(food = false) -} - -case class Cell(food: Int = 0, pher: Float = 0, ant: Option[Ant] = None, home: Boolean = false) { - def addFood(i: Int) = copy(food = food + i) - def addPher(x: Float) = copy(pher = pher + x) - def alterPher(f: Float ⇒ Float) = copy(pher = f(pher)) - def putAnt(antOpt: Option[Ant]) = copy(ant = antOpt) - def makeHome = copy(home = true) -} - -object EmptyCell extends Cell - -class Place(initCell: Cell = EmptyCell) extends Ref(initCell) { - def cell: Cell = getOrElse(EmptyCell) - def food: Int = cell.food - def food(i: Int) = alter(_.addFood(i)) - def hasFood = food > 0 - def pher: Float = cell.pher - def pher(f: Float ⇒ Float) = alter(_.alterPher(f)) - def trail = alter(_.addPher(1)) - def ant: Option[Ant] = cell.ant - def ant(f: Ant ⇒ Ant): Cell = alter(_.putAnt(ant map f)) - def enter(antOpt: Option[Ant]): Cell = alter(_.putAnt(antOpt)) - def enter(ant: Ant): Cell = enter(Some(ant)) - def leave = enter(None) - def occupied: Boolean = ant.isDefined - def makeHome = alter(_.makeHome) - def home: Boolean = cell.home -} - -case object Ping - -object World { - import Config._ - - val system = ActorSystem() - - val homeOff = Dim / 4 - lazy val places = Vector.fill(Dim, Dim)(new Place) - lazy val ants = setup - lazy val evaporator = system.actorOf[Evaporator] - - private val snapshotFactory = TransactionFactory(readonly = true, familyName = "snapshot") - - def snapshot = atomic(snapshotFactory) { Array.tabulate(Dim, Dim)(place(_, _).opt) } - - def place(loc: (Int, Int)) = places(loc._1)(loc._2) - - private def setup = atomic { - for (i ← 1 to FoodPlaces) { - place(randomInt(Dim), randomInt(Dim)) food (randomInt(FoodRange)) - } - val homeRange = homeOff until (AntsSqrt + homeOff) - for (x ← homeRange; y ← homeRange) yield { - place(x, y).makeHome - place(x, y) enter Ant(randomInt(8)) - system.actorOf(new AntActor(x, y)) - } - } - - def start = { - ants foreach pingEvery(AntMillis) - pingEvery(EvapMillis)(evaporator) - } - - private def pingEvery(millis: Long)(actor: ActorRef) = - system.scheduler.schedule(actor, Ping, Config.StartDelay, Duration(millis, TimeUnit.MILLISECONDS)) -} - -object Util { - import Config._ - - def bound(b: Int, n: Int) = { - val x = n % b - if (x < 0) x + b else x - } - - def dirBound(n: Int) = bound(8, n) - def dimBound(n: Int) = bound(Dim, n) - - val dirDelta = Map(0 -> (0, -1), 1 -> (1, -1), 2 -> (1, 0), 3 -> (1, 1), - 4 -> (0, 1), 5 -> (-1, 1), 6 -> (-1, 0), 7 -> (-1, -1)) - def deltaLoc(x: Int, y: Int, dir: Int) = { - val (dx, dy) = dirDelta(dirBound(dir)) - (dimBound(x + dx), dimBound(y + dy)) - } - - def rankBy[A, B: Ordering](xs: Seq[A], f: A ⇒ B) = Map(xs.sortBy(f).zip(Stream from 1): _*) - - def roulette(slices: Seq[Int]) = { - val total = slices.sum - val r = randomInt(total) - var i, sum = 0 - while ((sum + slices(i)) <= r) { - sum += slices(i) - i += 1 - } - i - } -} - -trait WorldActor extends Actor { - def act - def receive = { case Ping ⇒ act } -} - -class AntActor(initLoc: (Int, Int)) extends WorldActor { - import World._ - import Util._ - - val locRef = Ref(initLoc) - - val name = "ant-from-" + initLoc._1 + "-" + initLoc._2 - implicit val txFactory = TransactionFactory(familyName = name) - - val homing = (p: Place) ⇒ p.pher + (100 * (if (p.home) 0 else 1)) - val foraging = (p: Place) ⇒ p.pher + p.food - - def loc = locRef.getOrElse(initLoc) - def newLoc(l: (Int, Int)) = locRef swap l - - def act = atomic { - val (x, y) = loc - val current = place(x, y) - for (ant ← current.ant) { - val ahead = place(deltaLoc(x, y, ant.dir)) - if (ant.food) { // homing - if (current.home) dropFood - else if (ahead.home && !ahead.occupied) move - else random(homing) - } else { // foraging - if (!current.home && current.hasFood) pickUpFood - else if (!ahead.home && ahead.hasFood && !ahead.occupied) move - else random(foraging) - } - } - } - - def move = { - val (x, y) = loc - val from = place(x, y) - for (ant ← from.ant) { - val toLoc = deltaLoc(x, y, ant.dir) - val to = place(toLoc) - to enter ant - from.leave - if (!from.home) from.trail - newLoc(toLoc) - } - } - - def pickUpFood = { - val current = place(loc) - current food -1 - current ant (_.pickUp.turnAround) - } - - def dropFood = { - val current = place(loc) - current food +1 - current ant (_.dropOff.turnAround) - } - - def random[A: Ordering](ranking: Place ⇒ A) = { - val (x, y) = loc - val current = place(x, y) - for (ant ← current.ant) { - val delta = (turn: Int) ⇒ place(deltaLoc(x, y, ant.dir + turn)) - val ahead = delta(0) - val aheadLeft = delta(-1) - val aheadRight = delta(+1) - val locations = Seq(ahead, aheadLeft, aheadRight) - val ranks = rankBy(locations, ranking) - val ranked = Seq(ranks(aheadLeft), (if (ahead.occupied) 0 else ranks(ahead)), ranks(aheadRight)) - val dir = roulette(ranked) - 1 - if (dir == 0) move - else current ant (_.turn(dir)) - } - } -} - -class Evaporator extends WorldActor { - import Config._ - import World._ - - implicit val txFactory = TransactionFactory(familyName = "evaporator") - val evaporate = (pher: Float) ⇒ pher * EvapRate - - def act = for (x ← 0 until Dim; y ← 0 until Dim) { - atomic { place(x, y) pher evaporate } - } -} diff --git a/akka-samples/akka-sample-fsm/src/README b/akka-samples/akka-sample-fsm/README similarity index 100% rename from akka-samples/akka-sample-fsm/src/README rename to akka-samples/akka-sample-fsm/README diff --git a/akka-samples/akka-sample-hello/src/README b/akka-samples/akka-sample-hello/README similarity index 100% rename from akka-samples/akka-sample-hello/src/README rename to akka-samples/akka-sample-hello/README diff --git a/akka-samples/akka-sample-osgi/src/main/scala/OsgiExample.scala b/akka-samples/akka-sample-osgi/src/main/scala/OsgiExample.scala deleted file mode 100644 index bf257ffd49..0000000000 --- a/akka-samples/akka-sample-osgi/src/main/scala/OsgiExample.scala +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (C) 2009-2011 Typesafe Inc. - */ -package sample.osgi - -import org.osgi.framework.{ BundleActivator, BundleContext } -import akka.actor.{ Timeout, ActorSystem, Actor } - -class Activator extends BundleActivator { - val system = ActorSystem() - - def start(context: BundleContext) { - println("Starting the OSGi example ...") - val echo = system.actorOf[EchoActor] - val answer = (echo ? ("OSGi example", Timeout(100))).as[String] - println(answer getOrElse "No answer!") - } - - def stop(context: BundleContext) { - system.stop() - println("Stopped the OSGi example.") - } -} - -class EchoActor extends Actor { - override def receive = { - case x ⇒ sender ! x - } -} diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index e07570f620..5359a05e66 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -415,8 +415,6 @@ object Dependencies { // val sampleCamel = Seq(camelCore, camelSpring, commonsCodec, Runtime.camelJms, Runtime.activemq, Runtime.springJms, // Test.junit, Test.scalatest, Test.logback) - val sampleOsgi = Seq(osgi) - val tutorials = Seq(Test.scalatest, Test.junit) val docs = Seq(Test.scalatest, Test.junit) From 16dee0e481b01b567473a60a5a127f0cb1d3ed70 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Wed, 30 Nov 2011 18:05:11 +0100 Subject: [PATCH 13/23] #1409 - offsetting the raciness and also refrain from having a separate Timer for each Active connection handler --- .../main/scala/akka/actor/ActorSystem.scala | 4 +- .../remote/netty/NettyRemoteSupport.scala | 60 +++++++++---------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala index 4f02473b4f..0e9e8211cb 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala @@ -235,7 +235,7 @@ abstract class ActorSystem extends ActorRefFactory { * Register a block of code to run after all actors in this actor system have * been stopped. */ - def registerOnTermination(code: ⇒ Unit) + def registerOnTermination[T](code: ⇒ T) /** * Register a block of code to run after all actors in this actor system have @@ -354,7 +354,7 @@ class ActorSystemImpl(val name: String, val applicationConfig: Config) extends A def start() = _start - def registerOnTermination(code: ⇒ Unit) { terminationFuture onComplete (_ ⇒ code) } + def registerOnTermination[T](code: ⇒ T) { terminationFuture onComplete (_ ⇒ code) } def registerOnTermination(code: Runnable) { terminationFuture onComplete (_ ⇒ code.run) } // TODO shutdown all that other stuff, whatever that may be 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 d12f5ea7e4..2bf25c6186 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -59,35 +59,34 @@ abstract class RemoteClient private[akka] ( /** * Converts the message to the wireprotocol and sends the message across the wire */ - def send(message: Any, senderOption: Option[ActorRef], recipient: ActorRef): Unit = + def send(message: Any, senderOption: Option[ActorRef], recipient: ActorRef): Unit = if (isRunning) { send(remoteSupport.createRemoteMessageProtocolBuilder(Left(recipient), Right(message), senderOption).build) + } else { + val exception = new RemoteClientException("RemoteModule client is not running, make sure you have invoked 'RemoteClient.connect()' before using it.", remoteSupport, remoteAddress) + remoteSupport.notifyListeners(RemoteClientError(exception, remoteSupport, remoteAddress)) + throw exception + } /** * Sends the message across the wire */ - def send(request: RemoteMessageProtocol) { - if (isRunning) { //TODO FIXME RACY - log.debug("Sending message: " + new RemoteMessage(request, remoteSupport)) + def send(request: RemoteMessageProtocol): Unit = { + log.debug("Sending message: {}", new RemoteMessage(request, remoteSupport)) - try { - val payload = remoteSupport.createMessageSendEnvelope(request) - currentChannel.write(payload).addListener( - new ChannelFutureListener { - def operationComplete(future: ChannelFuture) { - if (future.isCancelled) { - //Not interesting at the moment - } else if (!future.isSuccess) { - remoteSupport.notifyListeners(RemoteClientWriteFailed(payload, future.getCause, remoteSupport, remoteAddress)) - } + try { + val payload = remoteSupport.createMessageSendEnvelope(request) + currentChannel.write(payload).addListener( + new ChannelFutureListener { + def operationComplete(future: ChannelFuture) { + if (future.isCancelled) { + //Not interesting at the moment + } else if (!future.isSuccess) { + remoteSupport.notifyListeners(RemoteClientWriteFailed(payload, future.getCause, remoteSupport, remoteAddress)) } - }) - } catch { - case e: Exception ⇒ remoteSupport.notifyListeners(RemoteClientError(e, remoteSupport, remoteAddress)) - } - } else { - val exception = new RemoteClientException("RemoteModule client is not running, make sure you have invoked 'RemoteClient.connect()' before using it.", remoteSupport, remoteAddress) - remoteSupport.notifyListeners(RemoteClientError(exception, remoteSupport, remoteAddress)) - throw exception + } + }) + } catch { + case e: Exception ⇒ remoteSupport.notifyListeners(RemoteClientError(e, remoteSupport, remoteAddress)) } } @@ -132,8 +131,7 @@ class ActiveRemoteClient private[akka] ( private[remote] var connection: ChannelFuture = _ @volatile private[remote] var openChannels: DefaultChannelGroup = _ - @volatile - private var timer: HashedWheelTimer = _ + @volatile private var reconnectionTimeWindowStart = 0L @@ -180,10 +178,9 @@ class ActiveRemoteClient private[akka] ( runSwitch switchOn { openChannels = new DefaultDisposableChannelGroup(classOf[RemoteClient].getName) - timer = new HashedWheelTimer bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool, Executors.newCachedThreadPool)) - bootstrap.setPipelineFactory(new ActiveRemoteClientPipelineFactory(name, bootstrap, remoteAddress, timer, this)) + bootstrap.setPipelineFactory(new ActiveRemoteClientPipelineFactory(name, bootstrap, remoteAddress, this)) bootstrap.setOption("tcpNoDelay", true) bootstrap.setOption("keepAlive", true) @@ -219,8 +216,6 @@ class ActiveRemoteClient private[akka] ( log.debug("Shutting down remote client [{}]", name) notifyListeners(RemoteClientShutdown(remoteSupport, remoteAddress)) - timer.stop() - timer = null openChannels.close.awaitUninterruptibly openChannels = null bootstrap.releaseExternalResources() @@ -253,18 +248,17 @@ class ActiveRemoteClientPipelineFactory( name: String, bootstrap: ClientBootstrap, remoteAddress: RemoteAddress, - timer: HashedWheelTimer, client: ActiveRemoteClient) extends ChannelPipelineFactory { import client.remoteSupport.clientSettings._ def getPipeline: ChannelPipeline = { - val timeout = new ReadTimeoutHandler(timer, ReadTimeout.length, ReadTimeout.unit) + val timeout = new ReadTimeoutHandler(client.remoteSupport.timer, ReadTimeout.length, ReadTimeout.unit) val lenDec = new LengthFieldBasedFrameDecoder(MessageFrameSize, 0, 4, 0, 4) val lenPrep = new LengthFieldPrepender(4) val protobufDec = new ProtobufDecoder(AkkaRemoteProtocol.getDefaultInstance) val protobufEnc = new ProtobufEncoder - val remoteClient = new ActiveRemoteClientHandler(name, bootstrap, remoteAddress, timer, client) + val remoteClient = new ActiveRemoteClientHandler(name, bootstrap, remoteAddress, client.remoteSupport.timer, client) new StaticChannelPipeline(timeout, lenDec, protobufDec, lenPrep, protobufEnc, remoteClient) } @@ -361,6 +355,10 @@ class NettyRemoteSupport(_system: ActorSystem) extends RemoteSupport(_system) wi val serverSettings = RemoteExtension(system).serverSettings val clientSettings = RemoteExtension(system).clientSettings + val timer: HashedWheelTimer = new HashedWheelTimer + + _system.registerOnTermination(timer.stop()) //Shut this guy down at the end + private val remoteClients = new HashMap[RemoteAddress, RemoteClient] private val clientsLock = new ReentrantReadWriteLock From b42c6b6bd1abcf3b468d7c6d8caff33d1ebe9d0b Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Wed, 30 Nov 2011 18:23:58 +0100 Subject: [PATCH 14/23] Adding the origin address to the SHUTDOWN CommandType when sent and also removed a wasteful FIXME --- .../main/scala/akka/remote/netty/NettyRemoteSupport.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 2bf25c6186..1f85b4683c 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -517,6 +517,10 @@ class NettyRemoteServer(val remoteSupport: NettyRemoteSupport, val loader: Optio try { val shutdownSignal = { val b = RemoteControlProtocol.newBuilder.setCommandType(CommandType.SHUTDOWN) + b.setOrigin(RemoteProtocol.AddressProtocol.newBuilder + .setHostname(address.hostname) + .setPort(address.port) + .build) if (SecureCookie.nonEmpty) b.setCookie(SecureCookie.get) b.build @@ -646,8 +650,8 @@ class RemoteServerHandler( val inbound = RemoteAddress(origin.getHostname, origin.getPort) val client = new PassiveRemoteClient(event.getChannel, remoteSupport, inbound) remoteSupport.bindClient(inbound, client) - case CommandType.SHUTDOWN ⇒ //TODO FIXME Dispose passive connection here - case _ ⇒ //Unknown command + case CommandType.SHUTDOWN ⇒ //No need to do anything here + case _ ⇒ //Unknown command } case _ ⇒ //ignore } From e590a4877a8e3fac570e8a82f8c90b538e5da7cc Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 1 Dec 2011 10:27:28 +0100 Subject: [PATCH 15/23] Making the ConsistencySpec a tad more awesomized --- .../scala/akka/actor/ConsistencySpec.scala | 19 +++++++++++++++---- .../remote/netty/NettyRemoteSupport.scala | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala index c04e193c2b..c3f1b772db 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala @@ -10,15 +10,22 @@ object ConsistencySpec { class ConsistencyCheckingActor extends Actor { var left = new CacheMisaligned(42, 0, 0, 0) //var var right = new CacheMisaligned(0, 0, 0, 0) //var + var lastStep = -1L def receive = { - case "check" ⇒ + case step: Long ⇒ + + if (lastStep != (step - 1)) + sender.tell("Test failed: Last step %s, this step %s".format(lastStep, step)) + var shouldBeFortyTwo = left.value + right.value if (shouldBeFortyTwo != 42) - sender ! "Test failed" + sender ! "Test failed: 42 failed" else { left.value += 1 right.value -= 1 } + + lastStep = step case "done" ⇒ sender ! "done"; self.stop() } } @@ -40,8 +47,12 @@ class ConsistencySpec extends AkkaSpec { val props = Props[ConsistencyCheckingActor].withDispatcher(dispatcher) val actors = Vector.fill(3)(system.actorOf(props)) - for (i ← 1 to 1000000) actors(i % actors.size).tell("check", testActor) - for (a ← actors) a.tell("done", testActor) + + for (i ← 0L until 1000000L) { + actors.foreach(_.tell(i, testActor)) + } + + for (a ← actors) { a.tell("done", testActor) } for (a ← actors) expectMsg(5 minutes, "done") } 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 1f85b4683c..2732cf1ebf 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -651,7 +651,7 @@ class RemoteServerHandler( val client = new PassiveRemoteClient(event.getChannel, remoteSupport, inbound) remoteSupport.bindClient(inbound, client) case CommandType.SHUTDOWN ⇒ //No need to do anything here - case _ ⇒ //Unknown command + case _ ⇒ //Unknown command } case _ ⇒ //ignore } From e3e694d1dcca5c66aaa98d6bfd7cc0bd2ef556a8 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 1 Dec 2011 17:02:30 +0100 Subject: [PATCH 16/23] Tweaking the consistency spec for using more cores --- .../src/test/scala/akka/actor/ConsistencySpec.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala index c3f1b772db..1118daff1c 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ConsistencySpec.scala @@ -35,10 +35,11 @@ class ConsistencySpec extends AkkaSpec { import ConsistencySpec._ "The Akka actor model implementation" must { "provide memory consistency" in { + val noOfActors = 7 val dispatcher = system .dispatcherFactory .newDispatcher("consistency-dispatcher", 1, UnboundedMailbox()) - .withNewThreadPoolWithArrayBlockingQueueWithCapacityAndFairness(1000, true) + .withNewThreadPoolWithArrayBlockingQueueWithCapacityAndFairness(noOfActors, true) .setCorePoolSize(10) .setMaxPoolSize(10) .setKeepAliveTimeInMillis(1) @@ -46,9 +47,9 @@ class ConsistencySpec extends AkkaSpec { .build val props = Props[ConsistencyCheckingActor].withDispatcher(dispatcher) - val actors = Vector.fill(3)(system.actorOf(props)) + val actors = Vector.fill(noOfActors)(system.actorOf(props)) - for (i ← 0L until 1000000L) { + for (i ← 0L until 600000L) { actors.foreach(_.tell(i, testActor)) } From ef27f865d456f2ab3c677c968157adb7b04ba2b0 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 1 Dec 2011 17:03:30 +0100 Subject: [PATCH 17/23] Adding support for ForkJoinPoolConfig so you can use ForkJoin --- .../akka/actor/dispatch/ActorModelSpec.scala | 36 ++++++++++++++ .../main/scala/akka/dispatch/Dispatcher.scala | 9 ++-- .../akka/dispatch/ThreadPoolBuilder.scala | 49 +++++++++++++++++++ 3 files changed, 88 insertions(+), 6 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala index e21f965c51..6b16042b69 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala @@ -492,3 +492,39 @@ class BalancingDispatcherModelSpec extends ActorModelSpec { } } } + +@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) +class FJDispatcherModelSpec extends ActorModelSpec { + import ActorModelSpec._ + + def newInterceptedDispatcher = + (new Dispatcher(system.dispatcherFactory.prerequisites, "foo", system.settings.DispatcherThroughput, + system.settings.DispatcherThroughputDeadlineTime, system.dispatcherFactory.MailboxType, + new ForkJoinPoolConfig(), system.settings.DispatcherDefaultShutdown) with MessageDispatcherInterceptor).asInstanceOf[MessageDispatcherInterceptor] + + def dispatcherType = "FJDispatcher" + + "A " + dispatcherType must { + "process messages in parallel" in { + implicit val dispatcher = newInterceptedDispatcher + val aStart, aStop, bParallel = new CountDownLatch(1) + val a, b = newTestActor(dispatcher) + + a ! Meet(aStart, aStop) + assertCountDown(aStart, 3.seconds.dilated.toMillis, "Should process first message within 3 seconds") + + b ! CountDown(bParallel) + assertCountDown(bParallel, 3.seconds.dilated.toMillis, "Should process other actors in parallel") + + aStop.countDown() + + a.stop + b.stop + + while (!a.isTerminated && !b.isTerminated) {} //Busy wait for termination + + assertRefDefaultZero(a)(registers = 1, unregisters = 1, msgsReceived = 1, msgsProcessed = 1) + assertRefDefaultZero(b)(registers = 1, unregisters = 1, msgsReceived = 1, msgsProcessed = 1) + } + } +} \ No newline at end of file diff --git a/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala b/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala index ee28fd586e..1a40ee23cd 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala @@ -6,12 +6,9 @@ package akka.dispatch import akka.event.Logging.Warning import java.util.concurrent.atomic.AtomicReference -import java.util.concurrent.{ TimeUnit, ExecutorService, RejectedExecutionException, ConcurrentLinkedQueue } -import akka.actor.{ ActorCell, ActorKilledException } -import akka.actor.ActorSystem -import akka.event.EventStream -import akka.actor.Scheduler +import akka.actor.ActorCell import akka.util.Duration +import java.util.concurrent._ /** * Default settings are: @@ -156,4 +153,4 @@ abstract class PriorityGenerator extends java.util.Comparator[Envelope] { final def compare(thisMessage: Envelope, thatMessage: Envelope): Int = gen(thisMessage.message) - gen(thatMessage.message) -} +} \ No newline at end of file diff --git a/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala b/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala index f543e5c016..f92be79b2d 100644 --- a/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala +++ b/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala @@ -11,6 +11,9 @@ import akka.event.Logging.{ Warning, Error } import akka.actor.ActorSystem import java.util.concurrent._ import akka.event.EventStream +import concurrent.forkjoin.ForkJoinPool._ +import concurrent.forkjoin.{ ForkJoinTask, ForkJoinWorkerThread, ForkJoinPool } +import concurrent.forkjoin.ForkJoinTask._ object ThreadPoolConfig { type Bounds = Int @@ -184,6 +187,52 @@ class MonitorableThread(runnable: Runnable, name: String) } } +case class ForkJoinPoolConfig(targetParallelism: Int = Runtime.getRuntime.availableProcessors()) extends ExecutorServiceFactoryProvider { + final def createExecutorServiceFactory(name: String): ExecutorServiceFactory = new ExecutorServiceFactory { + def createExecutorService: ExecutorService = { + new ForkJoinPool(targetParallelism) with ExecutorService { + setAsyncMode(true) + setMaintainsParallelism(true) + + override def execute(r: Runnable) { + r match { + case fjmbox: FJMailbox ⇒ + //fjmbox.fjTask.reinitialize() + Thread.currentThread match { + case fjwt: ForkJoinWorkerThread if fjwt.getPool eq this ⇒ + fjmbox.fjTask.fork() //We should do fjwt.pushTask(fjmbox.fjTask) but it's package protected + case _ ⇒ super.execute[Unit](fjmbox.fjTask) + } + case _ ⇒ + super.execute(r) + } + } + + import java.util.{ Collection ⇒ JCollection } + + def invokeAny[T](callables: JCollection[_ <: Callable[T]]) = + throw new UnsupportedOperationException("invokeAny. NOT!") + + def invokeAny[T](callables: JCollection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = + throw new UnsupportedOperationException("invokeAny. NOT!") + + def invokeAll[T](callables: JCollection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = + throw new UnsupportedOperationException("invokeAny. NOT!") + } + } + } +} + +trait FJMailbox { self: Mailbox ⇒ + val fjTask = new ForkJoinTask[Unit] with Runnable { + var result: Unit = () + def getRawResult() = result + def setRawResult(v: Unit) { result = v } + def exec() = { self.run(); true } + def run() { invoke() } + } +} + /** * As the name says */ From bf7befc6905930c4f1eabf2f868730b64c82ee73 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 1 Dec 2011 23:43:56 +0100 Subject: [PATCH 18/23] Sprinkling some final magic sauce --- .../scala/akka/dispatch/ThreadPoolBuilder.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala b/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala index f92be79b2d..c45cc74593 100644 --- a/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala +++ b/akka-actor/src/main/scala/akka/dispatch/ThreadPoolBuilder.scala @@ -194,7 +194,7 @@ case class ForkJoinPoolConfig(targetParallelism: Int = Runtime.getRuntime.availa setAsyncMode(true) setMaintainsParallelism(true) - override def execute(r: Runnable) { + override final def execute(r: Runnable) { r match { case fjmbox: FJMailbox ⇒ //fjmbox.fjTask.reinitialize() @@ -224,12 +224,12 @@ case class ForkJoinPoolConfig(targetParallelism: Int = Runtime.getRuntime.availa } trait FJMailbox { self: Mailbox ⇒ - val fjTask = new ForkJoinTask[Unit] with Runnable { - var result: Unit = () - def getRawResult() = result - def setRawResult(v: Unit) { result = v } - def exec() = { self.run(); true } - def run() { invoke() } + final val fjTask = new ForkJoinTask[Unit] with Runnable { + private[this] var result: Unit = () + final def getRawResult() = result + final def setRawResult(v: Unit) { result = v } + final def exec() = { self.run(); true } + final def run() { invoke() } } } From 571d856f5403caef5b7ee07c87900a6ec7c82238 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 1 Dec 2011 23:52:16 +0100 Subject: [PATCH 19/23] Removing one use-site of startsWatching --- .../test/scala/akka/actor/dispatch/ActorModelSpec.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala index 6b16042b69..f07ed9dfa1 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala @@ -341,9 +341,11 @@ abstract class ActorModelSpec extends AkkaSpec { val cachedMessage = CountDownNStop(new CountDownLatch(num)) val stopLatch = new CountDownLatch(num) val waitTime = (30 seconds).dilated.toMillis - val boss = actorOf(Props(context ⇒ { - case "run" ⇒ for (_ ← 1 to num) (context.self startsWatching context.actorOf(props)) ! cachedMessage - case Terminated(child) ⇒ stopLatch.countDown() + val boss = actorOf(Props(new Actor { + def receive = { + case "run" ⇒ for (_ ← 1 to num) (watch(context.actorOf(props))) ! cachedMessage + case Terminated(child) ⇒ stopLatch.countDown() + } }).withDispatcher(system.dispatcherFactory.newPinnedDispatcher("boss"))) boss ! "run" try { From 54e2e9a35740e46d33b3358348b50b0076286b5a Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Fri, 2 Dec 2011 00:25:17 +0100 Subject: [PATCH 20/23] Switching more test code to use watch instead of startsWatching --- .../src/test/scala/akka/actor/FSMTransitionSpec.scala | 2 +- .../src/test/scala/akka/actor/RestartStrategySpec.scala | 4 +--- .../src/test/scala/akka/actor/SupervisorHierarchySpec.scala | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/FSMTransitionSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/FSMTransitionSpec.scala index 917a65ec25..fdeabd2a47 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/FSMTransitionSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/FSMTransitionSpec.scala @@ -58,7 +58,7 @@ class FSMTransitionSpec extends AkkaSpec with ImplicitSender { val forward = actorOf(new Forwarder(testActor)) val fsm = actorOf(new MyFSM(testActor)) val sup = actorOf(Props(new Actor { - self startsWatching fsm + watch(fsm) def receive = { case _ ⇒ } }).withFaultHandler(OneForOneStrategy(List(classOf[Throwable]), None, None))) diff --git a/akka-actor-tests/src/test/scala/akka/actor/RestartStrategySpec.scala b/akka-actor-tests/src/test/scala/akka/actor/RestartStrategySpec.scala index f7ad0d34cb..dd9e9ac79f 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/RestartStrategySpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/RestartStrategySpec.scala @@ -206,7 +206,7 @@ class RestartStrategySpec extends AkkaSpec { val boss = actorOf(Props(new Actor { def receive = { - case p: Props ⇒ sender ! context.actorOf(p) + case p: Props ⇒ sender ! watch(context.actorOf(p)) case t: Terminated ⇒ maxNoOfRestartsLatch.open } }).withFaultHandler(OneForOneStrategy(List(classOf[Throwable]), None, Some(1000)))) @@ -228,8 +228,6 @@ class RestartStrategySpec extends AkkaSpec { }) val slave = (boss ? slaveProps).as[ActorRef].get - boss startsWatching slave - slave ! Ping slave ! Crash slave ! Ping diff --git a/akka-actor-tests/src/test/scala/akka/actor/SupervisorHierarchySpec.scala b/akka-actor-tests/src/test/scala/akka/actor/SupervisorHierarchySpec.scala index e3d2bf1eea..7b6299ab69 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/SupervisorHierarchySpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/SupervisorHierarchySpec.scala @@ -52,8 +52,7 @@ class SupervisorHierarchySpec extends AkkaSpec { val countDownMessages = new CountDownLatch(1) val countDownMax = new CountDownLatch(1) val boss = actorOf(Props(new Actor { - val crasher = context.actorOf(Props(new CountDownActor(countDownMessages))) - self startsWatching crasher + val crasher = watch(context.actorOf(Props(new CountDownActor(countDownMessages)))) protected def receive = { case "killCrasher" ⇒ crasher ! Kill From fcc6169edea2a0e89b47e0590404d56095b7eec6 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Fri, 2 Dec 2011 01:00:55 +0100 Subject: [PATCH 21/23] Removing the final usages of startsWatching/stopsWatching --- .../scala/akka/actor/DeathWatchSpec.scala | 34 +++++++--------- .../src/main/scala/akka/actor/Actor.scala | 10 ++--- .../src/main/scala/akka/actor/ActorCell.scala | 8 +++- .../src/main/scala/akka/actor/ActorRef.scala | 39 ------------------- .../akka/camel/component/ActorComponent.scala | 3 -- .../scala/akka/testkit/TestActorRef.scala | 18 +++++++++ .../scala/akka/testkit/TestActorRefSpec.scala | 5 ++- 7 files changed, 48 insertions(+), 69 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/DeathWatchSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/DeathWatchSpec.scala index 90e398e4cb..88b31f25d9 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/DeathWatchSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/DeathWatchSpec.scala @@ -11,6 +11,10 @@ import java.util.concurrent.atomic._ @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSender { + def startWatching(target: ActorRef) = actorOf(Props(new Actor { + watch(target) + def receive = { case x ⇒ testActor forward x } + })) "The Death Watch" must { def expectTerminationOf(actorRef: ActorRef) = expectMsgPF(5 seconds, actorRef + ": Stopped or Already terminated when linking") { @@ -19,8 +23,7 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende "notify with one Terminated message when an Actor is stopped" in { val terminal = actorOf(Props(context ⇒ { case _ ⇒ })) - - testActor startsWatching terminal + startWatching(terminal) testActor ! "ping" expectMsg("ping") @@ -32,11 +35,7 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende "notify with all monitors with one Terminated message when an Actor is stopped" in { val terminal = actorOf(Props(context ⇒ { case _ ⇒ })) - val monitor1, monitor2, monitor3 = - actorOf(Props(new Actor { - watch(terminal) - def receive = { case t: Terminated ⇒ testActor ! t } - })) + val monitor1, monitor2, monitor3 = startWatching(terminal) terminal ! PoisonPill @@ -51,11 +50,7 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende "notify with _current_ monitors with one Terminated message when an Actor is stopped" in { val terminal = actorOf(Props(context ⇒ { case _ ⇒ })) - val monitor1, monitor3 = - actorOf(Props(new Actor { - watch(terminal) - def receive = { case t: Terminated ⇒ testActor ! t } - })) + val monitor1, monitor3 = startWatching(terminal) val monitor2 = actorOf(Props(new Actor { watch(terminal) unwatch(terminal) @@ -85,10 +80,7 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende val terminalProps = Props(context ⇒ { case x ⇒ context.sender ! x }) val terminal = (supervisor ? terminalProps).as[ActorRef].get - val monitor = actorOf(Props(new Actor { - watch(terminal) - def receive = { case t: Terminated ⇒ testActor ! t } - })) + val monitor = startWatching(terminal) terminal ! Kill terminal ! Kill @@ -113,9 +105,13 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende } })) - val failed, brother = (supervisor ? Props.empty).as[ActorRef].get - brother startsWatching failed - testActor startsWatching brother + val failed = (supervisor ? Props.empty).as[ActorRef].get + val brother = (supervisor ? Props(new Actor { + watch(failed) + def receive = Actor.emptyBehavior + })).as[ActorRef].get + + startWatching(brother) failed ! Kill val result = receiveWhile(3 seconds, messages = 3) { diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index b8c0bbb327..8f613e02f5 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -363,24 +363,24 @@ trait Actor { * 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 */ - def become(behavior: Receive, discardOld: Boolean = true) { context.become(behavior, discardOld) } + final def become(behavior: Receive, discardOld: Boolean = true) { context.become(behavior, discardOld) } /** * Reverts the Actor behavior to the previous one in the hotswap stack. */ - def unbecome() { context.unbecome() } + final def unbecome() { context.unbecome() } /** * Registers this actor as a Monitor for the provided ActorRef * @return the provided ActorRef */ - def watch(subject: ActorRef): ActorRef = self startsWatching subject + final def watch(subject: ActorRef): ActorRef = context startsWatching subject /** * Unregisters this actor as Monitor for the provided ActorRef * @return the provided ActorRef */ - def unwatch(subject: ActorRef): ActorRef = self stopsWatching subject + final def unwatch(subject: ActorRef): ActorRef = context stopsWatching subject // ========================================= // ==== INTERNAL IMPLEMENTATION DETAILS ==== @@ -395,6 +395,6 @@ trait Actor { } } - private val processingBehavior = receive //ProcessingBehavior is the original behavior + private[this] val processingBehavior = receive //ProcessingBehavior is the original behavior } diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala index afd462ff1e..704d78d38b 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala @@ -47,6 +47,10 @@ trait ActorContext extends ActorRefFactory { def system: ActorSystem def parent: ActorRef + + def startsWatching(subject: ActorRef): ActorRef + + def stopsWatching(subject: ActorRef): ActorRef } private[akka] object ActorCell { @@ -136,13 +140,13 @@ private[akka] class ActorCell( // ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅ private[akka] def stop(): Unit = dispatcher.systemDispatch(this, Terminate()) - final def startsWatching(subject: ActorRef): ActorRef = { + override final def startsWatching(subject: ActorRef): ActorRef = { // ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅ dispatcher.systemDispatch(this, Link(subject)) subject } - final def stopsWatching(subject: ActorRef): ActorRef = { + override final def stopsWatching(subject: ActorRef): ActorRef = { // ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅ dispatcher.systemDispatch(this, Unlink(subject)) subject diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index e62a04938a..c86a2dc66e 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -128,24 +128,6 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable */ def isTerminated: Boolean - /** - * Registers this actor to be a death monitor of the provided ActorRef - * This means that this actor will get a Terminated()-message when the provided actor - * is permanently terminated. - * - * @return the same ActorRef that is provided to it, to allow for cleaner invocations - */ - def startsWatching(subject: ActorRef): ActorRef //TODO FIXME REMOVE THIS - - /** - * Deregisters this actor from being a death monitor of the provided ActorRef - * This means that this actor will not get a Terminated()-message when the provided actor - * is permanently terminated. - * - * @return the same ActorRef that is provided to it, to allow for cleaner invocations - */ - def stopsWatching(subject: ActorRef): ActorRef //TODO FIXME REMOVE THIS - override def hashCode: Int = HashCode.hash(HashCode.SEED, address) override def equals(that: Any): Boolean = { @@ -215,24 +197,6 @@ class LocalActorRef private[akka] ( */ def stop(): Unit = actorCell.stop() - /** - * Registers this actor to be a death monitor of the provided ActorRef - * This means that this actor will get a Terminated()-message when the provided actor - * is permanently terminated. - * - * @return the same ActorRef that is provided to it, to allow for cleaner invocations - */ - def startsWatching(subject: ActorRef): ActorRef = actorCell.startsWatching(subject) - - /** - * Deregisters this actor from being a death monitor of the provided ActorRef - * This means that this actor will not get a Terminated()-message when the provided actor - * is permanently terminated. - * - * @return the same ActorRef that is provided to it, to allow for cleaner invocations - */ - def stopsWatching(subject: ActorRef): ActorRef = actorCell.stopsWatching(subject) - // ========= AKKA PROTECTED FUNCTIONS ========= protected[akka] def underlying: ActorCell = actorCell @@ -330,9 +294,6 @@ trait MinimalActorRef extends ActorRef with ScalaActorRef { private[akka] val uuid: Uuid = newUuid() def name: String = uuid.toString - def startsWatching(actorRef: ActorRef): ActorRef = actorRef - def stopsWatching(actorRef: ActorRef): ActorRef = actorRef - def suspend(): Unit = () def resume(): Unit = () diff --git a/akka-camel/src/main/scala/akka/camel/component/ActorComponent.scala b/akka-camel/src/main/scala/akka/camel/component/ActorComponent.scala index 795fbf5a54..c4ec7dcf31 100644 --- a/akka-camel/src/main/scala/akka/camel/component/ActorComponent.scala +++ b/akka-camel/src/main/scala/akka/camel/component/ActorComponent.scala @@ -293,9 +293,6 @@ private[akka] class AsyncCallbackAdapter(exchange: Exchange, callback: AsyncCall callback.done(false) } - def startsWatching(actorRef: ActorRef): ActorRef = unsupported - def stopsWatching(actorRef: ActorRef): ActorRef = unsupported - def ?(message: Any)(implicit timeout: Timeout): Future[Any] = new KeptPromise[Any](Left(new UnsupportedOperationException("Ask/? is not supported for %s".format(getClass.getName)))) def restart(reason: Throwable): Unit = unsupported diff --git a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala index 6f03df59b2..18a181eb3f 100644 --- a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala +++ b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala @@ -42,6 +42,24 @@ class TestActorRef[T <: Actor]( */ def underlyingActor: T = underlyingActorInstance.asInstanceOf[T] + /** + * Registers this actor to be a death monitor of the provided ActorRef + * This means that this actor will get a Terminated()-message when the provided actor + * is permanently terminated. + * + * @return the same ActorRef that is provided to it, to allow for cleaner invocations + */ + def startsWatching(subject: ActorRef): ActorRef = underlying.startsWatching(subject) + + /** + * Deregisters this actor from being a death monitor of the provided ActorRef + * This means that this actor will not get a Terminated()-message when the provided actor + * is permanently terminated. + * + * @return the same ActorRef that is provided to it, to allow for cleaner invocations + */ + def stopsWatching(subject: ActorRef): ActorRef = underlying.stopsWatching(subject) + override def toString = "TestActor[" + address + "]" override def equals(other: Any) = other.isInstanceOf[TestActorRef[_]] && other.asInstanceOf[TestActorRef[_]].address == address diff --git a/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala b/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala index a6248ff63c..12096a61b1 100644 --- a/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala +++ b/akka-testkit/src/test/scala/akka/testkit/TestActorRefSpec.scala @@ -155,7 +155,10 @@ class TestActorRefSpec extends AkkaSpec with BeforeAndAfterEach { "stop when sent a poison pill" in { EventFilter[ActorKilledException]() intercept { val a = TestActorRef(Props[WorkerActor]) - testActor startsWatching a + val forwarder = actorOf(Props(new Actor { + watch(a) + def receive = { case x ⇒ testActor forward x } + })) a.!(PoisonPill)(testActor) expectMsgPF(5 seconds) { case Terminated(`a`) ⇒ true From 879ea7c2b4b2ecaeaca0651ec92d306bfa7aa6c2 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Fri, 2 Dec 2011 01:04:33 +0100 Subject: [PATCH 22/23] Removing startsWatching and stopsWatching from docs and removing cruft --- akka-docs/java/remote-actors.rst | 3 --- akka-docs/scala/remote-actors.rst | 3 --- .../main/scala/akka/remote/RemoteActorRefProvider.scala | 8 +------- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/akka-docs/java/remote-actors.rst b/akka-docs/java/remote-actors.rst index 745679c537..2147e03db1 100644 --- a/akka-docs/java/remote-actors.rst +++ b/akka-docs/java/remote-actors.rst @@ -178,10 +178,7 @@ The messages that it prevents are all that extends 'LifeCycleMessage': * case object ReceiveTimeout It also prevents the client from invoking any life-cycle and side-effecting methods, such as: -* start * stop -* startsWatching -* stopsWatching * etc. Using secure cookie for remote client authentication diff --git a/akka-docs/scala/remote-actors.rst b/akka-docs/scala/remote-actors.rst index ab2fe345c8..c408436b1e 100644 --- a/akka-docs/scala/remote-actors.rst +++ b/akka-docs/scala/remote-actors.rst @@ -180,10 +180,7 @@ The messages that it prevents are all that extends 'LifeCycleMessage': * class ReceiveTimeout..) It also prevents the client from invoking any life-cycle and side-effecting methods, such as: -* start * stop -* startsWatching -* stopsWatching * etc. Using secure cookie for remote client authentication diff --git a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala index 358568e13c..a10f8ca63a 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala @@ -296,7 +296,7 @@ private[akka] case class RemoteActorRef private[akka] ( def isTerminated: Boolean = !running - protected[akka] def sendSystemMessage(message: SystemMessage): Unit = unsupported + protected[akka] def sendSystemMessage(message: SystemMessage): Unit = throw new UnsupportedOperationException("Not supported for RemoteActorRef") override def !(message: Any)(implicit sender: ActorRef = null): Unit = remote.send(message, Option(sender), remoteAddress, this, loader) @@ -318,11 +318,5 @@ private[akka] case class RemoteActorRef private[akka] ( @throws(classOf[java.io.ObjectStreamException]) private def writeReplace(): AnyRef = provider.serialize(this) - def startsWatching(actorRef: ActorRef): ActorRef = unsupported //FIXME Implement - - def stopsWatching(actorRef: ActorRef): ActorRef = unsupported //FIXME Implement - protected[akka] def restart(cause: Throwable): Unit = () - - private def unsupported = throw new UnsupportedOperationException("Not supported for RemoteActorRef") } From d626cc24554cfada952d9f7aa45a0cbf35ba5405 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Fri, 2 Dec 2011 01:27:42 +0100 Subject: [PATCH 23/23] Removing suspend and resume from user-facing API --- .../src/main/scala/akka/actor/ActorRef.scala | 20 ++++++---------- .../main/scala/akka/actor/FaultHandling.scala | 10 ++++---- akka-docs/java/dispatchers.rst | 23 +++++++++---------- akka-docs/scala/dispatchers.rst | 19 ++++++--------- .../akka/remote/RemoteActorRefProvider.scala | 2 +- 5 files changed, 31 insertions(+), 43 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index c86a2dc66e..30a20ad769 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -46,7 +46,7 @@ import akka.event.DeathWatch * @author Jonas Bonér */ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable { - scalaRef: ScalaActorRef ⇒ + scalaRef: ScalaActorRef with RefInternals ⇒ // Only mutable for RemoteServer in order to maintain identity across nodes /** @@ -108,16 +108,6 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable */ def forward(message: Any)(implicit context: ActorContext) = tell(message, context.sender) - /** - * Suspends the actor. It will not process messages while suspended. - */ - def suspend(): Unit //TODO FIXME REMOVE THIS - - /** - * Resumes a suspended actor. - */ - def resume(): Unit //TODO FIXME REMOVE THIS - /** * Shuts down the actor its dispatcher and message queue. */ @@ -151,7 +141,7 @@ class LocalActorRef private[akka] ( val systemService: Boolean = false, _receiveTimeout: Option[Long] = None, _hotswap: Stack[PartialFunction[Any, Unit]] = Props.noHotSwap) - extends ActorRef with ScalaActorRef { + extends ActorRef with ScalaActorRef with RefInternals { def name = path.name @@ -260,7 +250,11 @@ trait ScalaActorRef { ref: ActorRef ⇒ * implicit timeout */ def ?(message: Any, timeout: Timeout)(implicit ignore: Int = 0): Future[Any] = ?(message)(timeout) +} +private[akka] trait RefInternals { + def resume(): Unit + def suspend(): Unit protected[akka] def restart(cause: Throwable): Unit } @@ -289,7 +283,7 @@ case class SerializedActorRef(hostname: String, port: Int, path: String) { /** * Trait for ActorRef implementations where all methods contain default stubs. */ -trait MinimalActorRef extends ActorRef with ScalaActorRef { +trait MinimalActorRef extends ActorRef with ScalaActorRef with RefInternals { private[akka] val uuid: Uuid = newUuid() def name: String = uuid.toString diff --git a/akka-actor/src/main/scala/akka/actor/FaultHandling.scala b/akka-actor/src/main/scala/akka/actor/FaultHandling.scala index 4656f5a3e3..b079550998 100644 --- a/akka-actor/src/main/scala/akka/actor/FaultHandling.scala +++ b/akka-actor/src/main/scala/akka/actor/FaultHandling.scala @@ -122,12 +122,12 @@ abstract class FaultHandlingStrategy { def handleSupervisorFailing(supervisor: ActorRef, children: Iterable[ActorRef]): Unit = { if (children.nonEmpty) - children.foreach(_.suspend()) + children.foreach(_.asInstanceOf[RefInternals].suspend()) } def handleSupervisorRestarted(cause: Throwable, supervisor: ActorRef, children: Iterable[ActorRef]): Unit = { if (children.nonEmpty) - children.foreach(_.restart(cause)) + children.foreach(_.asInstanceOf[RefInternals].restart(cause)) } /** @@ -136,7 +136,7 @@ abstract class FaultHandlingStrategy { def handleFailure(child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Boolean = { val action = if (decider.isDefinedAt(cause)) decider(cause) else Escalate action match { - case Resume ⇒ child.resume(); true + case Resume ⇒ child.asInstanceOf[RefInternals].resume(); true case Restart ⇒ processFailure(true, child, cause, stats, children); true case Stop ⇒ processFailure(false, child, cause, stats, children); true case Escalate ⇒ false @@ -194,7 +194,7 @@ case class AllForOneStrategy(decider: FaultHandlingStrategy.Decider, def processFailure(restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = { if (children.nonEmpty) { if (restart && children.forall(_.requestRestartPermission(retriesWindow))) - children.foreach(_.child.restart(cause)) + children.foreach(_.child.asInstanceOf[RefInternals].restart(cause)) else children.foreach(_.child.stop()) } @@ -247,7 +247,7 @@ case class OneForOneStrategy(decider: FaultHandlingStrategy.Decider, def processFailure(restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = { if (restart && stats.requestRestartPermission(retriesWindow)) - child.restart(cause) + child.asInstanceOf[RefInternals].restart(cause) else child.stop() //TODO optimization to drop child here already? } diff --git a/akka-docs/java/dispatchers.rst b/akka-docs/java/dispatchers.rst index d9f32f38c9..dc2684f9d8 100644 --- a/akka-docs/java/dispatchers.rst +++ b/akka-docs/java/dispatchers.rst @@ -155,6 +155,15 @@ Creating a Dispatcher with a priority mailbox using PriorityGenerator: public class Main { // A simple Actor that just prints the messages it processes public static class MyActor extends UntypedActor { + public MyActor() { + self.tell("lowpriority"); + getSelf().tell("lowpriority"); + getSelf().tell("highpriority"); + getSelf().tell("pigdog"); + getSelf().tell("pigdog2"); + getSelf().tell("pigdog3"); + getSelf().tell("highpriority"); + } public void onReceive(Object message) throws Exception { System.out.println(message); } @@ -170,19 +179,9 @@ Creating a Dispatcher with a priority mailbox using PriorityGenerator: } }; // We create an instance of the actor that will print out the messages it processes - ActorRef ref = Actors.actorOf(MyActor.class); - // We create a new Priority dispatcher and seed it with the priority generator - ref.setDispatcher(new Dispatcher("foo", 5, new UnboundedPriorityMailbox(gen))); + // We create a new Priority dispatcher and seed it with the priority generator + ActorRef ref = Actors.actorOf((new Props()).withCreator(MyActor.class).withDispatcher(new Dispatcher("foo", 5, new UnboundedPriorityMailbox(gen)))); - ref.getDispatcher().suspend(ref); // Suspending the actor so it doesn't start to treat the messages before we have enqueued all of them :-) - ref.tell("lowpriority"); - ref.tell("lowpriority"); - ref.tell("highpriority"); - ref.tell("pigdog"); - ref.tell("pigdog2"); - ref.tell("pigdog3"); - ref.tell("highpriority"); - ref.getDispatcher().resume(ref); // Resuming the actor so it will start treating its messages } } diff --git a/akka-docs/scala/dispatchers.rst b/akka-docs/scala/dispatchers.rst index fa00c746f5..e16c336753 100644 --- a/akka-docs/scala/dispatchers.rst +++ b/akka-docs/scala/dispatchers.rst @@ -155,23 +155,18 @@ Creating a Dispatcher using PriorityGenerator: val a = Actor.actorOf( // We create a new Actor that just prints out what it processes Props(new Actor { + self ! 'lowpriority + self ! 'lowpriority + self ! 'highpriority + self ! 'pigdog + self ! 'pigdog2 + self ! 'pigdog3 + self ! 'highpriority def receive = { case x => println(x) } }).withDispatcher(new Dispatcher("foo", 5, UnboundedPriorityMailbox(gen)))) // We create a new Priority dispatcher and seed it with the priority generator - 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 - a ! 'highpriority - a ! 'pigdog - a ! 'pigdog2 - a ! 'pigdog3 - a ! 'highpriority - - a.dispatcher.resume(a) // Resuming the actor so it will start treating its messages - Prints: 'highpriority diff --git a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala index a10f8ca63a..385a27f29a 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala @@ -285,7 +285,7 @@ private[akka] case class RemoteActorRef private[akka] ( remoteAddress: RemoteAddress, path: ActorPath, loader: Option[ClassLoader]) - extends ActorRef with ScalaActorRef { + extends ActorRef with ScalaActorRef with RefInternals { @volatile private var running: Boolean = true