Updated samples and tutorial to Akka 2.0. Added projects to SBT project file. Fixes #1278
This commit is contained in:
parent
c0d3c523e2
commit
823a68ac0f
33 changed files with 1291 additions and 1209 deletions
|
|
@ -11,6 +11,7 @@ import scala.annotation.tailrec
|
||||||
import java.util.concurrent.atomic.{ AtomicReference, AtomicInteger }
|
import java.util.concurrent.atomic.{ AtomicReference, AtomicInteger }
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import akka.remote.RemoteAddress
|
import akka.remote.RemoteAddress
|
||||||
|
import collection.JavaConverters
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Iterable that also contains a version.
|
* An Iterable that also contains a version.
|
||||||
|
|
@ -85,6 +86,10 @@ trait ConnectionManager {
|
||||||
*/
|
*/
|
||||||
class LocalConnectionManager(initialConnections: Iterable[ActorRef]) extends 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] {
|
case class State(version: Long, connections: Iterable[ActorRef]) extends VersionedIterable[ActorRef] {
|
||||||
def iterable = connections
|
def iterable = connections
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import java.lang.reflect.InvocationTargetException
|
||||||
import java.util.concurrent.atomic.{ AtomicReference, AtomicInteger }
|
import java.util.concurrent.atomic.{ AtomicReference, AtomicInteger }
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
import akka.japi.Creator
|
||||||
|
|
||||||
sealed trait RouterType
|
sealed trait RouterType
|
||||||
|
|
||||||
|
|
@ -66,11 +67,17 @@ object RouterType {
|
||||||
* Contains the configuration to create local and clustered routed actor references.
|
* Contains the configuration to create local and clustered routed actor references.
|
||||||
* Routed ActorRef configuration object, this is thread safe and fully sharable.
|
* 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,
|
routerFactory: () ⇒ Router = RoutedProps.defaultRouterFactory,
|
||||||
connectionManager: ConnectionManager = new LocalConnectionManager(List()),
|
connectionManager: ConnectionManager = new LocalConnectionManager(List()),
|
||||||
timeout: Timeout = RoutedProps.defaultTimeout,
|
timeout: Timeout = RoutedProps.defaultTimeout,
|
||||||
localOnly: Boolean = RoutedProps.defaultLocalOnly) {
|
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 {
|
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
|
* 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.
|
* 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
|
val path = supervisor.path / name
|
||||||
|
|
||||||
|
|
@ -346,7 +353,7 @@ class RandomRouter extends BasicRouter {
|
||||||
*
|
*
|
||||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||||
*/
|
*/
|
||||||
class RoundRobinRouter extends BasicRouter {
|
private[akka] class RoundRobinRouter extends BasicRouter {
|
||||||
|
|
||||||
private val state = new AtomicReference[RoundRobinState]
|
private val state = new AtomicReference[RoundRobinState]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,8 @@ abstract class RemoteClient private[akka] (
|
||||||
}
|
}
|
||||||
|
|
||||||
class PassiveRemoteClient(val currentChannel: Channel,
|
class PassiveRemoteClient(val currentChannel: Channel,
|
||||||
remoteSupport: NettyRemoteSupport,
|
remoteSupport: NettyRemoteSupport,
|
||||||
remoteAddress: RemoteAddress)
|
remoteAddress: RemoteAddress)
|
||||||
extends RemoteClient(remoteSupport, remoteAddress) {
|
extends RemoteClient(remoteSupport, remoteAddress) {
|
||||||
|
|
||||||
def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = runSwitch switchOn {
|
def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = runSwitch switchOn {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ trait NetworkFailureSpec { self: AkkaSpec ⇒
|
||||||
|
|
||||||
val BytesPerSecond = "60KByte/s"
|
val BytesPerSecond = "60KByte/s"
|
||||||
val DelayMillis = "350ms"
|
val DelayMillis = "350ms"
|
||||||
val PortRang = "1024-65535"
|
val PortRange = "1024-65535"
|
||||||
|
|
||||||
def replyWithTcpResetFor(duration: Duration, dead: AtomicBoolean) = {
|
def replyWithTcpResetFor(duration: Duration, dead: AtomicBoolean) = {
|
||||||
Future {
|
Future {
|
||||||
|
|
@ -82,12 +82,12 @@ trait NetworkFailureSpec { self: AkkaSpec ⇒
|
||||||
|
|
||||||
def enableNetworkDrop() = {
|
def enableNetworkDrop() = {
|
||||||
restoreIP()
|
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() = {
|
def enableTcpReset() = {
|
||||||
restoreIP()
|
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() = {
|
def restoreIP() = {
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ By using this software in any fashion, you are agreeing to be bound by
|
||||||
the terms of this license.
|
the terms of this license.
|
||||||
You must not remove this notice, or any other, from this software.
|
You must not remove this notice, or any other, from this software.
|
||||||
|
|
||||||
[ants.clj]:http://clojure.googlegroups.com/web/ants.clj
|
[ants.clj]: http://clojure.googlegroups.com/web/ants.clj
|
||||||
[akka]:http://akkasource.org
|
[akka]: http://akka.io
|
||||||
[spde]:http://technically.us/spde/
|
[spde]: http://technically.us/spde/
|
||||||
[sbt]: http://code.google.com/p/simple-build-tool/
|
[sbt]: http://code.google.com/p/simple-build-tool/
|
||||||
[cpl]: http://opensource.org/licenses/cpl1.0.php
|
[cpl]: http://opensource.org/licenses/cpl1.0.php
|
||||||
|
|
@ -4,22 +4,23 @@
|
||||||
|
|
||||||
package sample.ants
|
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 java.util.concurrent.TimeUnit
|
||||||
import scala.util.Random.{nextInt => randomInt}
|
|
||||||
import akka.actor.{Actor, ActorRef, Scheduler}
|
|
||||||
import akka.actor.Actor.actorOf
|
|
||||||
import akka.stm._
|
import akka.stm._
|
||||||
|
|
||||||
object Config {
|
object Config {
|
||||||
val Dim = 80 // dimensions of square world
|
val Dim = 80 // dimensions of square world
|
||||||
val AntsSqrt = 20 // number of ants = AntsSqrt^2
|
val AntsSqrt = 20 // number of ants = AntsSqrt^2
|
||||||
val FoodPlaces = 35 // number of places with food
|
val FoodPlaces = 35 // number of places with food
|
||||||
val FoodRange = 100 // range of amount of food at a place
|
val FoodRange = 100 // range of amount of food at a place
|
||||||
val PherScale = 10 // scale factor for pheromone drawing
|
val PherScale = 10 // scale factor for pheromone drawing
|
||||||
val AntMillis = 100 // how often an ant behaves (milliseconds)
|
val AntMillis = 100 // how often an ant behaves (milliseconds)
|
||||||
val EvapMillis = 1000 // how often pheromone evaporation occurs (milliseconds)
|
val EvapMillis = 1000 // how often pheromone evaporation occurs (milliseconds)
|
||||||
val EvapRate = 0.99f // pheromone evaporation rate
|
val EvapRate = 0.99f // pheromone evaporation rate
|
||||||
val StartDelay = 1000 // delay before everything kicks off (milliseconds)
|
val StartDelay = 1000 milliseconds // delay before everything kicks off (milliseconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Ant(dir: Int, food: Boolean = false) {
|
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) {
|
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 addFood(i: Int) = copy(food = food + i)
|
||||||
def addPher(x: Float) = copy(pher = pher + x)
|
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 putAnt(antOpt: Option[Ant]) = copy(ant = antOpt)
|
||||||
def makeHome = copy(home = true)
|
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 food(i: Int) = alter(_.addFood(i))
|
||||||
def hasFood = food > 0
|
def hasFood = food > 0
|
||||||
def pher: Float = cell.pher
|
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 trail = alter(_.addPher(1))
|
||||||
def ant: Option[Ant] = cell.ant
|
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(antOpt: Option[Ant]): Cell = alter(_.putAnt(antOpt))
|
||||||
def enter(ant: Ant): Cell = enter(Some(ant))
|
def enter(ant: Ant): Cell = enter(Some(ant))
|
||||||
def leave = enter(None)
|
def leave = enter(None)
|
||||||
|
|
@ -62,10 +63,12 @@ case object Ping
|
||||||
object World {
|
object World {
|
||||||
import Config._
|
import Config._
|
||||||
|
|
||||||
|
val system = ActorSystem()
|
||||||
|
|
||||||
val homeOff = Dim / 4
|
val homeOff = Dim / 4
|
||||||
lazy val places = Vector.fill(Dim, Dim)(new Place)
|
lazy val places = Vector.fill(Dim, Dim)(new Place)
|
||||||
lazy val ants = setup
|
lazy val ants = setup
|
||||||
lazy val evaporator = actorOf[Evaporator]
|
lazy val evaporator = system.actorOf[Evaporator]
|
||||||
|
|
||||||
private val snapshotFactory = TransactionFactory(readonly = true, familyName = "snapshot")
|
private val snapshotFactory = TransactionFactory(readonly = true, familyName = "snapshot")
|
||||||
|
|
||||||
|
|
@ -74,14 +77,14 @@ object World {
|
||||||
def place(loc: (Int, Int)) = places(loc._1)(loc._2)
|
def place(loc: (Int, Int)) = places(loc._1)(loc._2)
|
||||||
|
|
||||||
private def setup = atomic {
|
private def setup = atomic {
|
||||||
for (i <- 1 to FoodPlaces) {
|
for (i ← 1 to FoodPlaces) {
|
||||||
place(randomInt(Dim), randomInt(Dim)) food (randomInt(FoodRange))
|
place(randomInt(Dim), randomInt(Dim)) food (randomInt(FoodRange))
|
||||||
}
|
}
|
||||||
val homeRange = homeOff until (AntsSqrt + homeOff)
|
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).makeHome
|
||||||
place(x, y) enter Ant(randomInt(8))
|
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) =
|
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 {
|
object Util {
|
||||||
|
|
@ -106,13 +109,13 @@ object Util {
|
||||||
def dimBound(n: Int) = bound(Dim, n)
|
def dimBound(n: Int) = bound(Dim, n)
|
||||||
|
|
||||||
val dirDelta = Map(0 -> (0, -1), 1 -> (1, -1), 2 -> (1, 0), 3 -> (1, 1),
|
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) = {
|
def deltaLoc(x: Int, y: Int, dir: Int) = {
|
||||||
val (dx, dy) = dirDelta(dirBound(dir))
|
val (dx, dy) = dirDelta(dirBound(dir))
|
||||||
(dimBound(x + dx), dimBound(y + dy))
|
(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]) = {
|
def roulette(slices: Seq[Int]) = {
|
||||||
val total = slices.sum
|
val total = slices.sum
|
||||||
|
|
@ -128,7 +131,7 @@ object Util {
|
||||||
|
|
||||||
trait WorldActor extends Actor {
|
trait WorldActor extends Actor {
|
||||||
def act
|
def act
|
||||||
def receive = { case Ping => act }
|
def receive = { case Ping ⇒ act }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AntActor(initLoc: (Int, Int)) extends WorldActor {
|
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
|
val name = "ant-from-" + initLoc._1 + "-" + initLoc._2
|
||||||
implicit val txFactory = TransactionFactory(familyName = name)
|
implicit val txFactory = TransactionFactory(familyName = name)
|
||||||
|
|
||||||
val homing = (p: Place) => p.pher + (100 * (if (p.home) 0 else 1))
|
val homing = (p: Place) ⇒ p.pher + (100 * (if (p.home) 0 else 1))
|
||||||
val foraging = (p: Place) => p.pher + p.food
|
val foraging = (p: Place) ⇒ p.pher + p.food
|
||||||
|
|
||||||
def loc = locRef.getOrElse(initLoc)
|
def loc = locRef.getOrElse(initLoc)
|
||||||
def newLoc(l: (Int, Int)) = locRef swap l
|
def newLoc(l: (Int, Int)) = locRef swap l
|
||||||
|
|
@ -149,7 +152,7 @@ class AntActor(initLoc: (Int, Int)) extends WorldActor {
|
||||||
def act = atomic {
|
def act = atomic {
|
||||||
val (x, y) = loc
|
val (x, y) = loc
|
||||||
val current = place(x, y)
|
val current = place(x, y)
|
||||||
for (ant <- current.ant) {
|
for (ant ← current.ant) {
|
||||||
val ahead = place(deltaLoc(x, y, ant.dir))
|
val ahead = place(deltaLoc(x, y, ant.dir))
|
||||||
if (ant.food) { // homing
|
if (ant.food) { // homing
|
||||||
if (current.home) dropFood
|
if (current.home) dropFood
|
||||||
|
|
@ -166,7 +169,7 @@ class AntActor(initLoc: (Int, Int)) extends WorldActor {
|
||||||
def move = {
|
def move = {
|
||||||
val (x, y) = loc
|
val (x, y) = loc
|
||||||
val from = place(x, y)
|
val from = place(x, y)
|
||||||
for (ant <- from.ant) {
|
for (ant ← from.ant) {
|
||||||
val toLoc = deltaLoc(x, y, ant.dir)
|
val toLoc = deltaLoc(x, y, ant.dir)
|
||||||
val to = place(toLoc)
|
val to = place(toLoc)
|
||||||
to enter ant
|
to enter ant
|
||||||
|
|
@ -188,11 +191,11 @@ class AntActor(initLoc: (Int, Int)) extends WorldActor {
|
||||||
current ant (_.dropOff.turnAround)
|
current ant (_.dropOff.turnAround)
|
||||||
}
|
}
|
||||||
|
|
||||||
def random[A: Ordering](ranking: Place => A) = {
|
def random[A: Ordering](ranking: Place ⇒ A) = {
|
||||||
val (x, y) = loc
|
val (x, y) = loc
|
||||||
val current = place(x, y)
|
val current = place(x, y)
|
||||||
for (ant <- current.ant) {
|
for (ant ← current.ant) {
|
||||||
val delta = (turn: Int) => place(deltaLoc(x, y, ant.dir + turn))
|
val delta = (turn: Int) ⇒ place(deltaLoc(x, y, ant.dir + turn))
|
||||||
val ahead = delta(0)
|
val ahead = delta(0)
|
||||||
val aheadLeft = delta(-1)
|
val aheadLeft = delta(-1)
|
||||||
val aheadRight = delta(+1)
|
val aheadRight = delta(+1)
|
||||||
|
|
@ -211,9 +214,9 @@ class Evaporator extends WorldActor {
|
||||||
import World._
|
import World._
|
||||||
|
|
||||||
implicit val txFactory = TransactionFactory(familyName = "evaporator")
|
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 }
|
atomic { place(x, y) pher evaporate }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
*/
|
*/
|
||||||
class RemoteActor1 extends Actor with Consumer {
|
|
||||||
def endpointUri = "jetty:http://localhost:6644/camel/remote-actor-1"
|
|
||||||
|
|
||||||
protected def receive = {
|
// CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0
|
||||||
case msg: Message ⇒ sender ! Message("hello %s" format msg.bodyAs[String], Map("sender" -> "remote1"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
//package sample.camel
|
||||||
* Server-initiated remote actor.
|
//
|
||||||
*/
|
//import org.apache.camel.Exchange
|
||||||
class RemoteActor2 extends Actor with Consumer {
|
//
|
||||||
def endpointUri = "jetty:http://localhost:6644/camel/remote-actor-2"
|
//import akka.actor.{ Actor, ActorRef, ActorRegistry }
|
||||||
|
//import akka.camel.{ Ack, Failure, Producer, Message, Consumer }
|
||||||
protected def receive = {
|
//
|
||||||
case msg: Message ⇒ sender ! Message("hello %s" format msg.bodyAs[String], Map("sender" -> "remote2"))
|
///**
|
||||||
}
|
// * Client-initiated remote actor.
|
||||||
}
|
// */
|
||||||
|
//class RemoteActor1 extends Actor with Consumer {
|
||||||
class Producer1 extends Actor with Producer {
|
// def endpointUri = "jetty:http://localhost:6644/camel/remote-actor-1"
|
||||||
def endpointUri = "direct:welcome"
|
//
|
||||||
override def oneway = false // default
|
// protected def receive = {
|
||||||
}
|
// case msg: Message ⇒ sender ! Message("hello %s" format msg.bodyAs[String], Map("sender" -> "remote1"))
|
||||||
|
// }
|
||||||
class Consumer1 extends Actor with Consumer {
|
//}
|
||||||
def endpointUri = "file:data/input/actor"
|
//
|
||||||
|
///**
|
||||||
def receive = {
|
// * Server-initiated remote actor.
|
||||||
case msg: Message ⇒ println("received %s" format msg.bodyAs[String])
|
// */
|
||||||
}
|
//class RemoteActor2 extends Actor with Consumer {
|
||||||
}
|
// def endpointUri = "jetty:http://localhost:6644/camel/remote-actor-2"
|
||||||
|
//
|
||||||
class Consumer2 extends Actor with Consumer {
|
// protected def receive = {
|
||||||
def endpointUri = "jetty:http://0.0.0.0:8877/camel/default"
|
// case msg: Message ⇒ sender ! Message("hello %s" format msg.bodyAs[String], Map("sender" -> "remote2"))
|
||||||
|
// }
|
||||||
def receive = {
|
//}
|
||||||
case msg: Message ⇒ sender ! ("Hello %s" format msg.bodyAs[String])
|
//
|
||||||
}
|
//class Producer1 extends Actor with Producer {
|
||||||
}
|
// def endpointUri = "direct:welcome"
|
||||||
|
// override def oneway = false // default
|
||||||
class Consumer3(transformer: ActorRef) extends Actor with Consumer {
|
//}
|
||||||
def endpointUri = "jetty:http://0.0.0.0:8877/camel/welcome"
|
//
|
||||||
|
//class Consumer1 extends Actor with Consumer {
|
||||||
def receive = {
|
// def endpointUri = "file:data/input/actor"
|
||||||
case msg: Message ⇒ transformer.forward(msg.setBodyAs[String])
|
//
|
||||||
}
|
// def receive = {
|
||||||
}
|
// case msg: Message ⇒ println("received %s" format msg.bodyAs[String])
|
||||||
|
// }
|
||||||
class Consumer4 extends Actor with Consumer {
|
//}
|
||||||
def endpointUri = "jetty:http://0.0.0.0:8877/camel/stop"
|
//
|
||||||
|
//class Consumer2 extends Actor with Consumer {
|
||||||
def receive = {
|
// def endpointUri = "jetty:http://0.0.0.0:8877/camel/default"
|
||||||
case msg: Message ⇒ msg.bodyAs[String] match {
|
//
|
||||||
case "stop" ⇒ {
|
// def receive = {
|
||||||
sender ! "Consumer4 stopped"
|
// case msg: Message ⇒ sender ! ("Hello %s" format msg.bodyAs[String])
|
||||||
self.stop
|
// }
|
||||||
}
|
//}
|
||||||
case body ⇒ sender ! body
|
//
|
||||||
}
|
//class Consumer3(transformer: ActorRef) extends Actor with Consumer {
|
||||||
}
|
// def endpointUri = "jetty:http://0.0.0.0:8877/camel/welcome"
|
||||||
}
|
//
|
||||||
|
// def receive = {
|
||||||
class Consumer5 extends Actor with Consumer {
|
// case msg: Message ⇒ transformer.forward(msg.setBodyAs[String])
|
||||||
def endpointUri = "jetty:http://0.0.0.0:8877/camel/start"
|
// }
|
||||||
|
//}
|
||||||
def receive = {
|
//
|
||||||
case _ ⇒ {
|
//class Consumer4 extends Actor with Consumer {
|
||||||
Actor.actorOf[Consumer4]
|
// def endpointUri = "jetty:http://0.0.0.0:8877/camel/stop"
|
||||||
sender ! "Consumer4 started"
|
//
|
||||||
}
|
// def receive = {
|
||||||
}
|
// case msg: Message ⇒ msg.bodyAs[String] match {
|
||||||
}
|
// case "stop" ⇒ {
|
||||||
|
// sender ! "Consumer4 stopped"
|
||||||
class Transformer(producer: ActorRef) extends Actor {
|
// self.stop
|
||||||
protected def receive = {
|
// }
|
||||||
case msg: Message ⇒ producer.forward(msg.transformBody((body: String) ⇒ "- %s -" format body))
|
// case body ⇒ sender ! body
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//}
|
||||||
class Subscriber(name: String, uri: String) extends Actor with Consumer {
|
//
|
||||||
def endpointUri = uri
|
//class Consumer5 extends Actor with Consumer {
|
||||||
|
// def endpointUri = "jetty:http://0.0.0.0:8877/camel/start"
|
||||||
protected def receive = {
|
//
|
||||||
case msg: Message ⇒ println("%s received: %s" format (name, msg.body))
|
// def receive = {
|
||||||
}
|
// case _ ⇒ {
|
||||||
}
|
// Actor.actorOf[Consumer4]
|
||||||
|
// sender ! "Consumer4 started"
|
||||||
class Publisher(uri: String) extends Actor with Producer {
|
// }
|
||||||
def endpointUri = uri
|
// }
|
||||||
override def oneway = true
|
//}
|
||||||
}
|
//
|
||||||
|
//class Transformer(producer: ActorRef) extends Actor {
|
||||||
class PublisherBridge(uri: String, publisher: ActorRef) extends Actor with Consumer {
|
// protected def receive = {
|
||||||
def endpointUri = uri
|
// case msg: Message ⇒ producer.forward(msg.transformBody((body: String) ⇒ "- %s -" format body))
|
||||||
|
// }
|
||||||
protected def receive = {
|
//}
|
||||||
case msg: Message ⇒ {
|
//
|
||||||
publisher ! msg.bodyAs[String]
|
//class Subscriber(name: String, uri: String) extends Actor with Consumer {
|
||||||
sender ! "message published"
|
// def endpointUri = uri
|
||||||
}
|
//
|
||||||
}
|
// protected def receive = {
|
||||||
}
|
// case msg: Message ⇒ println("%s received: %s" format (name, msg.body))
|
||||||
|
// }
|
||||||
class HttpConsumer(producer: ActorRef) extends Actor with Consumer {
|
//}
|
||||||
def endpointUri = "jetty:http://0.0.0.0:8875/"
|
//
|
||||||
|
//class Publisher(uri: String) extends Actor with Producer {
|
||||||
protected def receive = {
|
// def endpointUri = uri
|
||||||
case msg ⇒ producer forward msg
|
// override def oneway = true
|
||||||
}
|
//}
|
||||||
}
|
//
|
||||||
|
//class PublisherBridge(uri: String, publisher: ActorRef) extends Actor with Consumer {
|
||||||
class HttpProducer(transformer: ActorRef) extends Actor with Producer {
|
// def endpointUri = uri
|
||||||
def endpointUri = "jetty://http://akka.io/?bridgeEndpoint=true"
|
//
|
||||||
|
// protected def receive = {
|
||||||
override protected def receiveBeforeProduce = {
|
// case msg: Message ⇒ {
|
||||||
// only keep Exchange.HTTP_PATH message header (which needed by bridge endpoint)
|
// publisher ! msg.bodyAs[String]
|
||||||
case msg: Message ⇒ msg.setHeaders(msg.headers(Set(Exchange.HTTP_PATH)))
|
// sender ! "message published"
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
override protected def receiveAfterProduce = {
|
//}
|
||||||
// do not reply but forward result to transformer
|
//
|
||||||
case msg ⇒ transformer forward msg
|
//class HttpConsumer(producer: ActorRef) extends Actor with Consumer {
|
||||||
}
|
// def endpointUri = "jetty:http://0.0.0.0:8875/"
|
||||||
}
|
//
|
||||||
|
// protected def receive = {
|
||||||
class HttpTransformer extends Actor {
|
// case msg ⇒ producer forward msg
|
||||||
protected def receive = {
|
// }
|
||||||
case msg: Message ⇒ sender ! (msg.transformBody { body: String ⇒ body replaceAll ("Akka ", "AKKA ") })
|
//}
|
||||||
case msg: Failure ⇒ sender ! msg
|
//
|
||||||
}
|
//class HttpProducer(transformer: ActorRef) extends Actor with Producer {
|
||||||
}
|
// def endpointUri = "jetty://http://akka.io/?bridgeEndpoint=true"
|
||||||
|
//
|
||||||
class FileConsumer extends Actor with Consumer {
|
// override protected def receiveBeforeProduce = {
|
||||||
def endpointUri = "file:data/input/actor?delete=true"
|
// // only keep Exchange.HTTP_PATH message header (which needed by bridge endpoint)
|
||||||
override def autoack = false
|
// case msg: Message ⇒ msg.setHeaders(msg.headers(Set(Exchange.HTTP_PATH)))
|
||||||
|
// }
|
||||||
var counter = 0
|
//
|
||||||
|
// override protected def receiveAfterProduce = {
|
||||||
def receive = {
|
// // do not reply but forward result to transformer
|
||||||
case msg: Message ⇒ {
|
// case msg ⇒ transformer forward msg
|
||||||
if (counter == 2) {
|
// }
|
||||||
println("received %s" format msg.bodyAs[String])
|
//}
|
||||||
sender ! Ack
|
//
|
||||||
} else {
|
//class HttpTransformer extends Actor {
|
||||||
println("rejected %s" format msg.bodyAs[String])
|
// protected def receive = {
|
||||||
counter += 1
|
// case msg: Message ⇒ sender ! (msg.transformBody { body: String ⇒ body replaceAll ("Akka ", "AKKA ") })
|
||||||
sender ! Failure(new Exception("message number %s not accepted" format counter))
|
// 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))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
||||||
|
|
@ -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
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
*/
|
*/
|
||||||
class Boot {
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0
|
||||||
// Basic example
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
actorOf[Consumer1]
|
//package sample.camel
|
||||||
actorOf[Consumer2]
|
//
|
||||||
|
//import org.apache.camel.{ Exchange, Processor }
|
||||||
// -----------------------------------------------------------------------
|
//import org.apache.camel.builder.RouteBuilder
|
||||||
// Custom Camel route example
|
//import org.apache.camel.impl.DefaultCamelContext
|
||||||
// -----------------------------------------------------------------------
|
//import org.apache.camel.spring.spi.ApplicationContextRegistry
|
||||||
|
//import org.springframework.context.support.ClassPathXmlApplicationContext
|
||||||
// Create CamelContext and a Spring-based registry
|
//
|
||||||
val context = new ClassPathXmlApplicationContext("/context-jms.xml", getClass)
|
//import akka.actor.Actor._
|
||||||
val registry = new ApplicationContextRegistry(context)
|
//import akka.actor.Props
|
||||||
|
//import akka.actor.TypedActor
|
||||||
// Use a custom Camel context and a custom touter builder
|
//import akka.camel.CamelContextManager
|
||||||
CamelContextManager.init(new DefaultCamelContext(registry))
|
//
|
||||||
CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder)
|
///**
|
||||||
|
// * @author Martin Krasser
|
||||||
val producer = actorOf[Producer1]
|
// */
|
||||||
val mediator = actorOf(new Transformer(producer))
|
//class Boot {
|
||||||
val consumer = actorOf(new Consumer3(mediator))
|
//
|
||||||
|
// // -----------------------------------------------------------------------
|
||||||
// -----------------------------------------------------------------------
|
// // Basic example
|
||||||
// Asynchronous consumer-producer example (Akka homepage transformation)
|
// // -----------------------------------------------------------------------
|
||||||
// -----------------------------------------------------------------------
|
//
|
||||||
|
// actorOf[Consumer1]
|
||||||
val httpTransformer = actorOf(new HttpTransformer)
|
// actorOf[Consumer2]
|
||||||
val httpProducer = actorOf(new HttpProducer(httpTransformer))
|
//
|
||||||
val httpConsumer = actorOf(new HttpConsumer(httpProducer))
|
// // -----------------------------------------------------------------------
|
||||||
|
// // Custom Camel route example
|
||||||
// -----------------------------------------------------------------------
|
// // -----------------------------------------------------------------------
|
||||||
// Publish subscribe examples
|
//
|
||||||
// -----------------------------------------------------------------------
|
// // Create CamelContext and a Spring-based registry
|
||||||
|
// val context = new ClassPathXmlApplicationContext("/context-jms.xml", getClass)
|
||||||
//
|
// val registry = new ApplicationContextRegistry(context)
|
||||||
// Cometd example commented out because camel-cometd is broken since Camel 2.3
|
//
|
||||||
//
|
// // Use a custom Camel context and a custom touter builder
|
||||||
|
// CamelContextManager.init(new DefaultCamelContext(registry))
|
||||||
//val cometdUri = "cometd://localhost:8111/test/abc?baseResource=file:target"
|
// CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder)
|
||||||
//val cometdSubscriber = actorOf(new Subscriber("cometd-subscriber", cometdUri))
|
//
|
||||||
//val cometdPublisher = actorOf(new Publisher("cometd-publisher", cometdUri))
|
// val producer = actorOf[Producer1]
|
||||||
|
// val mediator = actorOf(new Transformer(producer))
|
||||||
val jmsUri = "jms:topic:test"
|
// val consumer = actorOf(new Consumer3(mediator))
|
||||||
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")
|
// // Asynchronous consumer-producer example (Akka homepage transformation)
|
||||||
|
// // -----------------------------------------------------------------------
|
||||||
//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))
|
// val httpTransformer = actorOf(new HttpTransformer)
|
||||||
|
// val httpProducer = actorOf(new HttpProducer(httpTransformer))
|
||||||
// -----------------------------------------------------------------------
|
// val httpConsumer = actorOf(new HttpConsumer(httpProducer))
|
||||||
// Actor un-publishing and re-publishing example
|
//
|
||||||
// -----------------------------------------------------------------------
|
// // -----------------------------------------------------------------------
|
||||||
|
// // Publish subscribe examples
|
||||||
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.
|
//
|
||||||
|
// //
|
||||||
// -----------------------------------------------------------------------
|
// // Cometd example commented out because camel-cometd is broken since Camel 2.3
|
||||||
// Active object example
|
// //
|
||||||
// -----------------------------------------------------------------------
|
//
|
||||||
|
// //val cometdUri = "cometd://localhost:8111/test/abc?baseResource=file:target"
|
||||||
// TODO: investigate why this consumer is not published
|
// //val cometdSubscriber = actorOf(new Subscriber("cometd-subscriber", cometdUri))
|
||||||
TypedActor.typedActorOf(classOf[TypedConsumer1], classOf[TypedConsumer1Impl], Props())
|
// //val cometdPublisher = actorOf(new Publisher("cometd-publisher", cometdUri))
|
||||||
}
|
//
|
||||||
|
// val jmsUri = "jms:topic:test"
|
||||||
/**
|
// val jmsSubscriber1 = actorOf(new Subscriber("jms-subscriber-1", jmsUri))
|
||||||
* @author Martin Krasser
|
// val jmsSubscriber2 = actorOf(new Subscriber("jms-subscriber-2", jmsUri))
|
||||||
*/
|
// val jmsPublisher = actorOf(new Publisher(jmsUri), "jms-publisher")
|
||||||
class CustomRouteBuilder extends RouteBuilder {
|
//
|
||||||
def configure {
|
// //val cometdPublisherBridge = actorOf(new PublisherBridge("jetty:http://0.0.0.0:8877/camel/pub/cometd", cometdPublisher))
|
||||||
val actorUri = "actor:%s" format classOf[Consumer2].getName
|
// val jmsPublisherBridge = actorOf(new PublisherBridge("jetty:http://0.0.0.0:8877/camel/pub/jms", jmsPublisher))
|
||||||
from("jetty:http://0.0.0.0:8877/camel/custom").to(actorUri)
|
//
|
||||||
from("direct:welcome").process(new Processor() {
|
// // -----------------------------------------------------------------------
|
||||||
def process(exchange: Exchange) {
|
// // Actor un-publishing and re-publishing example
|
||||||
exchange.getOut.setBody("Welcome %s" format exchange.getIn.getBody)
|
// // -----------------------------------------------------------------------
|
||||||
}
|
//
|
||||||
})
|
// 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)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,35 @@
|
||||||
package sample.camel
|
|
||||||
|
|
||||||
import akka.actor.Actor._
|
|
||||||
import akka.actor.TypedActor
|
|
||||||
import akka.camel.Message
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Martin Krasser
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
*/
|
|
||||||
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
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// */
|
||||||
|
//}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,33 @@
|
||||||
package sample.camel
|
|
||||||
|
|
||||||
import akka.actor.Actor._
|
|
||||||
import akka.camel.CamelServiceManager
|
|
||||||
import akka.actor.{ TypedActor, Props }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Martin Krasser
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
*/
|
|
||||||
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)
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
}
|
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
// */
|
||||||
|
//}
|
||||||
|
|
|
||||||
|
|
@ -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
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
*/
|
*/
|
||||||
object StandaloneApplication extends App {
|
|
||||||
import CamelContextManager._
|
|
||||||
import CamelServiceManager._
|
|
||||||
|
|
||||||
// 'externally' register typed actors
|
// CAMEL IS NOT PART OF MILESTONE 1 OF AKKA 2.0
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//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)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
|
|
||||||
|
|
@ -1,253 +1,256 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sample.chat
|
// REMOTING IS NOT PART OF MILESTONE 1 OF AKKA 2.0
|
||||||
|
|
||||||
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=<root of distribution>.
|
|
||||||
- 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("<your name>")
|
|
||||||
- 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.
|
|
||||||
* <p/>
|
|
||||||
* 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.
|
|
||||||
* <p/>
|
|
||||||
* 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:
|
|
||||||
* <pre>
|
|
||||||
* val chatService = Actor.actorOf[ChatService]
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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=<root of distribution>.
|
||||||
|
// - 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("<your name>")
|
||||||
|
// - 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.
|
||||||
|
// * <p/>
|
||||||
|
// * 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.
|
||||||
|
// * <p/>
|
||||||
|
// * 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:
|
||||||
|
// * <pre>
|
||||||
|
// * val chatService = Actor.actorOf[ChatService]
|
||||||
|
// * </pre>
|
||||||
|
// */
|
||||||
|
// 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
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
|
||||||
30
akka-samples/akka-sample-fsm/src/README
Normal file
30
akka-samples/akka-sample-fsm/src/README
Normal file
|
|
@ -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/
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
|
*/
|
||||||
package sample.fsm.buncher
|
package sample.fsm.buncher
|
||||||
|
|
||||||
import akka.actor.ActorRefFactory
|
import akka.actor.ActorRefFactory
|
||||||
|
|
@ -6,15 +9,15 @@ import akka.util.Duration
|
||||||
import akka.actor.{ FSM, Actor, ActorRef }
|
import akka.actor.{ FSM, Actor, ActorRef }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generic typed object buncher.
|
* generic typed object buncher.
|
||||||
*
|
*
|
||||||
* To instantiate it, use the factory method like so:
|
* To instantiate it, use the factory method like so:
|
||||||
* Buncher(100, 500)(x : List[AnyRef] => x foreach println)
|
* Buncher(100, 500)(x : List[AnyRef] => x foreach println)
|
||||||
* which will yield a fully functional ActorRef.
|
* which will yield a fully functional ActorRef.
|
||||||
* The type of messages allowed is strongly typed to match the
|
* The type of messages allowed is strongly typed to match the
|
||||||
* supplied processing method; other messages are discarded (and
|
* supplied processing method; other messages are discarded (and
|
||||||
* possibly logged).
|
* possibly logged).
|
||||||
*/
|
*/
|
||||||
object GenericBuncher {
|
object GenericBuncher {
|
||||||
trait State
|
trait State
|
||||||
case object Idle extends State
|
case object Idle extends State
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
|
*/
|
||||||
package sample.fsm.dining.become
|
package sample.fsm.dining.become
|
||||||
|
|
||||||
//Akka adaptation of
|
//Akka adaptation of
|
||||||
|
|
@ -7,8 +10,8 @@ import akka.actor.{ ActorRef, Actor, ActorSystem }
|
||||||
import akka.util.duration._
|
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
|
sealed trait DiningHakkerMessage
|
||||||
case class Busy(chopstick: ActorRef) extends DiningHakkerMessage
|
case class Busy(chopstick: ActorRef) extends DiningHakkerMessage
|
||||||
case class Put(hakker: ActorRef) extends DiningHakkerMessage
|
case class Put(hakker: ActorRef) extends DiningHakkerMessage
|
||||||
|
|
@ -18,9 +21,9 @@ object Eat extends DiningHakkerMessage
|
||||||
object Think extends DiningHakkerMessage
|
object Think extends DiningHakkerMessage
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A Chopstick is an actor, it can be taken, and put back
|
* A Chopstick is an actor, it can be taken, and put back
|
||||||
*/
|
*/
|
||||||
class Chopstick(name: String) extends Actor {
|
class Chopstick extends Actor {
|
||||||
|
|
||||||
//When a Chopstick is taken by a hakker
|
//When a Chopstick is taken by a hakker
|
||||||
//It will refuse to be taken by other hakkers
|
//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 {
|
class Hakker(name: String, left: ActorRef, right: ActorRef) extends Actor {
|
||||||
|
|
||||||
//When a hakker is thinking it can become hungry
|
//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 :-)
|
//back to think about how he should obtain his chopsticks :-)
|
||||||
def waiting_for(chopstickToWaitFor: ActorRef, otherChopstick: ActorRef): Receive = {
|
def waiting_for(chopstickToWaitFor: ActorRef, otherChopstick: ActorRef): Receive = {
|
||||||
case Taken(`chopstickToWaitFor`) ⇒
|
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)
|
become(eating)
|
||||||
system.scheduler.scheduleOnce(self, Think, 5 seconds)
|
system.scheduler.scheduleOnce(self, Think, 5 seconds)
|
||||||
|
|
||||||
|
|
@ -105,27 +108,33 @@ class Hakker(name: String, left: ActorRef, right: ActorRef) extends Actor {
|
||||||
become(thinking)
|
become(thinking)
|
||||||
left ! Put(self)
|
left ! Put(self)
|
||||||
right ! 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)
|
system.scheduler.scheduleOnce(self, Eat, 5 seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
//All hakkers start in a non-eating state
|
//All hakkers start in a non-eating state
|
||||||
def receive = {
|
def receive = {
|
||||||
case Think ⇒
|
case Think ⇒
|
||||||
println("%s starts to think", name)
|
println("%s starts to think".format(name))
|
||||||
become(thinking)
|
become(thinking)
|
||||||
system.scheduler.scheduleOnce(self, Eat, 5 seconds)
|
system.scheduler.scheduleOnce(self, Eat, 5 seconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Alright, here's our test-harness
|
* Alright, here's our test-harness
|
||||||
*/
|
*/
|
||||||
object DiningHakkers {
|
object DiningHakkers {
|
||||||
val system = ActorSystem()
|
val system = ActorSystem()
|
||||||
|
|
||||||
|
def main(args: Array[String]) {
|
||||||
|
run
|
||||||
|
}
|
||||||
|
|
||||||
def run {
|
def run {
|
||||||
//Create 5 chopsticks
|
//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
|
//Create 5 awesome hakkers and assign them their left and right chopstick
|
||||||
val hakkers = for {
|
val hakkers = for {
|
||||||
(name, i) ← List("Ghosh", "Bonér", "Klang", "Krasser", "Manie").zipWithIndex
|
(name, i) ← List("Ghosh", "Bonér", "Klang", "Krasser", "Manie").zipWithIndex
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2009-2010 Typesafe Inc. <http://www.typesafe.com>.
|
||||||
|
*/
|
||||||
package sample.fsm.dining.fsm
|
package sample.fsm.dining.fsm
|
||||||
|
|
||||||
import akka.actor.{ ActorRef, Actor, FSM, ActorSystem }
|
import akka.actor.{ ActorRef, Actor, FSM, ActorSystem }
|
||||||
|
|
@ -6,8 +9,8 @@ import akka.util.Duration
|
||||||
import akka.util.duration._
|
import akka.util.duration._
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some messages for the chopstick
|
* Some messages for the chopstick
|
||||||
*/
|
*/
|
||||||
sealed trait ChopstickMessage
|
sealed trait ChopstickMessage
|
||||||
object Take extends ChopstickMessage
|
object Take extends ChopstickMessage
|
||||||
object Put extends ChopstickMessage
|
object Put extends ChopstickMessage
|
||||||
|
|
@ -27,9 +30,9 @@ case object Taken extends ChopstickState
|
||||||
case class TakenBy(hakker: ActorRef)
|
case class TakenBy(hakker: ActorRef)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A chopstick is an actor, it can be taken, and put back
|
* A chopstick is an actor, it can be taken, and put back
|
||||||
*/
|
*/
|
||||||
class Chopstick(name: String) extends Actor with FSM[ChopstickState, TakenBy] {
|
class Chopstick extends Actor with FSM[ChopstickState, TakenBy] {
|
||||||
|
|
||||||
// A chopstick begins its existence as available and taken by no one
|
// A chopstick begins its existence as available and taken by no one
|
||||||
startWith(Available, TakenBy(system.deadLetters))
|
startWith(Available, TakenBy(system.deadLetters))
|
||||||
|
|
@ -77,8 +80,8 @@ case object Eating extends FSMHakkerState
|
||||||
case class TakenChopsticks(left: Option[ActorRef], right: Option[ActorRef])
|
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] {
|
class FSMHakker(name: String, left: ActorRef, right: ActorRef) extends Actor with FSM[FSMHakkerState, TakenChopsticks] {
|
||||||
|
|
||||||
//All hakkers start waiting
|
//All hakkers start waiting
|
||||||
|
|
@ -86,7 +89,7 @@ class FSMHakker(name: String, left: ActorRef, right: ActorRef) extends Actor wit
|
||||||
|
|
||||||
when(Waiting) {
|
when(Waiting) {
|
||||||
case Event(Think, _) ⇒
|
case Event(Think, _) ⇒
|
||||||
println("%s starts to think", name)
|
println("%s starts to think".format(name))
|
||||||
startThinking(5 seconds)
|
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 = {
|
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)
|
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
|
// then he puts down his chopsticks and starts to think
|
||||||
when(Eating) {
|
when(Eating) {
|
||||||
case Event(StateTimeout, _) ⇒
|
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
|
left ! Put
|
||||||
right ! Put
|
right ! Put
|
||||||
startThinking(5 seconds)
|
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 {
|
object DiningHakkersOnFsm {
|
||||||
|
|
||||||
val system = ActorSystem()
|
val system = ActorSystem()
|
||||||
|
|
||||||
|
def main(args: Array[String]) {
|
||||||
|
run
|
||||||
|
}
|
||||||
|
|
||||||
def run = {
|
def run = {
|
||||||
// Create 5 chopsticks
|
// 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
|
// Create 5 awesome fsm hakkers and assign them their left and right chopstick
|
||||||
val hakkers = for {
|
val hakkers = for {
|
||||||
(name, i) ← List("Ghosh", "Bonér", "Klang", "Krasser", "Manie").zipWithIndex
|
(name, i) ← List("Ghosh", "Bonér", "Klang", "Krasser", "Manie").zipWithIndex
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
|
||||||
|
|
||||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
|
||||||
|
|
||||||
<!-- =========================================================== -->
|
|
||||||
<!-- Server Thread Pool -->
|
|
||||||
<!-- =========================================================== -->
|
|
||||||
<Set name="ThreadPool">
|
|
||||||
<New class="org.eclipse.jetty.util.thread.ExecutorThreadPool">
|
|
||||||
</New>
|
|
||||||
</Set>
|
|
||||||
|
|
||||||
<!-- =========================================================== -->
|
|
||||||
<!-- Set connectors -->
|
|
||||||
<!-- =========================================================== -->
|
|
||||||
|
|
||||||
<Call name="addConnector">
|
|
||||||
<Arg>
|
|
||||||
<New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
|
|
||||||
<Set name="host"><SystemProperty name="jetty.host" /></Set>
|
|
||||||
<Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
|
|
||||||
<Set name="maxIdleTime">300000</Set>
|
|
||||||
<Set name="Acceptors">2</Set>
|
|
||||||
<Set name="statsOn">false</Set>
|
|
||||||
<Set name="confidentialPort">8443</Set>
|
|
||||||
<Set name="lowResourcesConnections">20000</Set>
|
|
||||||
<Set name="lowResourcesMaxIdleTime">5000</Set>
|
|
||||||
</New>
|
|
||||||
</Arg>
|
|
||||||
</Call>
|
|
||||||
|
|
||||||
<!-- =========================================================== -->
|
|
||||||
<!-- Set handler -->
|
|
||||||
<!-- =========================================================== -->
|
|
||||||
<Set name="handler">
|
|
||||||
<New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
|
|
||||||
<Set name="handlers">
|
|
||||||
<Array type="org.eclipse.jetty.server.Handler">
|
|
||||||
<Item>
|
|
||||||
<New id="AkkaMistHandler" class="org.eclipse.jetty.servlet.ServletContextHandler">
|
|
||||||
<Set name="contextPath">/</Set>
|
|
||||||
<Call name="addServlet">
|
|
||||||
<Arg>akka.http.AkkaMistServlet</Arg>
|
|
||||||
<Arg>/*</Arg>
|
|
||||||
</Call>
|
|
||||||
</New>
|
|
||||||
</Item>
|
|
||||||
<Item>
|
|
||||||
<New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
|
|
||||||
</Item>
|
|
||||||
</Array>
|
|
||||||
</Set>
|
|
||||||
</New>
|
|
||||||
</Set>
|
|
||||||
|
|
||||||
<!-- =========================================================== -->
|
|
||||||
<!-- Extra options -->
|
|
||||||
<!-- =========================================================== -->
|
|
||||||
<Set name="stopAtShutdown">true</Set>
|
|
||||||
<Set name="sendServerVersion">true</Set>
|
|
||||||
<Set name="sendDateHeader">true</Set>
|
|
||||||
<Set name="gracefulShutdown">1000</Set>
|
|
||||||
|
|
||||||
</Configure>
|
|
||||||
28
akka-samples/akka-sample-hello/src/README
Normal file
28
akka-samples/akka-sample-hello/src/README
Normal file
|
|
@ -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/
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
||||||
|
*/
|
||||||
|
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!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -3,29 +3,27 @@
|
||||||
*/
|
*/
|
||||||
package sample.osgi
|
package sample.osgi
|
||||||
|
|
||||||
import akka.actor.Actor
|
|
||||||
import akka.actor.Actor._
|
|
||||||
|
|
||||||
import org.osgi.framework.{ BundleActivator, BundleContext }
|
import org.osgi.framework.{ BundleActivator, BundleContext }
|
||||||
|
import akka.actor.{ Timeout, ActorSystem, Actor }
|
||||||
|
|
||||||
class Activator extends BundleActivator {
|
class Activator extends BundleActivator {
|
||||||
|
val system = ActorSystem()
|
||||||
|
|
||||||
def start(context: BundleContext) {
|
def start(context: BundleContext) {
|
||||||
println("Starting the OSGi example ...")
|
println("Starting the OSGi example ...")
|
||||||
val echo = actorOf[EchoActor]
|
val echo = system.actorOf[EchoActor]
|
||||||
val answer = (echo ? "OSGi example").as[String]
|
val answer = (echo ? ("OSGi example", Timeout(100))).as[String]
|
||||||
println(answer getOrElse "No answer!")
|
println(answer getOrElse "No answer!")
|
||||||
}
|
}
|
||||||
|
|
||||||
def stop(context: BundleContext) {
|
def stop(context: BundleContext) {
|
||||||
Actor.registry.local.shutdownAll()
|
system.stop()
|
||||||
println("Stopped the OSGi example.")
|
println("Stopped the OSGi example.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EchoActor extends Actor {
|
class EchoActor extends Actor {
|
||||||
|
|
||||||
override def receive = {
|
override def receive = {
|
||||||
case x => reply(x)
|
case x ⇒ sender ! x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,35 +2,37 @@
|
||||||
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sample.remote
|
// REMOTING IS NOT PART OF MILESTONE 1 OF AKKA 2.0
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//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
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>se.scalablesolutions.akka</groupId>
|
<groupId>com.typesafe.akka</groupId>
|
||||||
<artifactId>akka-actor</artifactId>
|
<artifactId>akka-actor</artifactId>
|
||||||
<version>2.0-SNAPSHOT</version>
|
<version>2.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1 @@
|
||||||
project.organization=se.scalablesolutions.akka
|
sbt.version=0.11.0
|
||||||
project.name=akka-tutorial-first
|
|
||||||
project.version=2.0-SNAPSHOT
|
|
||||||
build.scala.versions=2.9.0
|
|
||||||
sbt.version=0.7.7
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
import sbt._
|
|
||||||
|
|
||||||
class TutorialOneProject(info: ProjectInfo) extends DefaultProject(info) with AkkaProject
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -1,182 +1,184 @@
|
||||||
// *
|
/**
|
||||||
// * Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 java.util.LinkedList;
|
||||||
// import static java.util.Arrays.asList;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
// import akka.actor.ActorRef;
|
public class Pi {
|
||||||
// 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;
|
|
||||||
|
|
||||||
// import java.util.LinkedList;
|
private static final ActorSystem system = ActorSystem.apply();
|
||||||
// import java.util.concurrent.CountDownLatch;
|
|
||||||
|
|
||||||
// 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 {
|
static class Work {
|
||||||
// Pi pi = new Pi();
|
private final int start;
|
||||||
// pi.calculate(4, 10000, 10000);
|
private final int nrOfElements;
|
||||||
// }
|
|
||||||
|
|
||||||
// // ====================
|
public Work(int start, int nrOfElements) {
|
||||||
// // ===== Messages =====
|
this.start = start;
|
||||||
// // ====================
|
this.nrOfElements = nrOfElements;
|
||||||
// static class Calculate {}
|
}
|
||||||
|
|
||||||
// static class Work {
|
public int getStart() {
|
||||||
// private final int start;
|
return start;
|
||||||
// private final int nrOfElements;
|
}
|
||||||
|
|
||||||
// public Work(int start, int nrOfElements) {
|
public int getNrOfElements() {
|
||||||
// this.start = start;
|
return nrOfElements;
|
||||||
// this.nrOfElements = nrOfElements;
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// public int getStart() { return start; }
|
static class Result {
|
||||||
// public int getNrOfElements() { return nrOfElements; }
|
private final double value;
|
||||||
// }
|
|
||||||
|
|
||||||
// static class Result {
|
public Result(double value) {
|
||||||
// private final double value;
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
// public Result(double value) {
|
public double getValue() {
|
||||||
// this.value = value;
|
return value;
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// public double getValue() { return value; }
|
// ==================
|
||||||
// }
|
// ===== Worker =====
|
||||||
|
// ==================
|
||||||
|
public static class Worker extends UntypedActor {
|
||||||
|
|
||||||
// // ==================
|
// define the work
|
||||||
// // ===== Worker =====
|
private double calculatePiFor(int start, int nrOfElements) {
|
||||||
// // ==================
|
double acc = 0.0;
|
||||||
// static class Worker extends UntypedActor {
|
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
|
// message handler
|
||||||
// private double calculatePiFor(int start, int nrOfElements) {
|
public void onReceive(Object message) {
|
||||||
// double acc = 0.0;
|
if (message instanceof Work) {
|
||||||
// for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
|
Work work = (Work) message;
|
||||||
// acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1);
|
|
||||||
// }
|
|
||||||
// return acc;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // message handler
|
// perform the work
|
||||||
// public void onReceive(Object message) {
|
double result = calculatePiFor(work.getStart(), work.getNrOfElements());
|
||||||
// if (message instanceof Work) {
|
|
||||||
// Work work = (Work) message;
|
|
||||||
|
|
||||||
// // perform the work
|
// reply with the result
|
||||||
// double result = calculatePiFor(work.getStart(), work.getNrOfElements());
|
getSender().tell(new Result(result));
|
||||||
|
|
||||||
// // reply with the result
|
} else throw new IllegalArgumentException("Unknown message [" + message + "]");
|
||||||
// getSender().tell(new Result(result));
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// } 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;
|
||||||
|
|
||||||
// // ==================
|
private double pi;
|
||||||
// // ===== Master =====
|
private int nrOfResults;
|
||||||
// // ==================
|
private long start;
|
||||||
// static class Master extends UntypedActor {
|
|
||||||
// private final int nrOfMessages;
|
|
||||||
// private final int nrOfElements;
|
|
||||||
// private final CountDownLatch latch;
|
|
||||||
|
|
||||||
// private double pi;
|
private ActorRef router;
|
||||||
// private int nrOfResults;
|
|
||||||
// private long start;
|
|
||||||
|
|
||||||
// private ActorRef router;
|
public Master(final int nrOfWorkers, int nrOfMessages, int nrOfElements, CountDownLatch latch) {
|
||||||
|
this.nrOfMessages = nrOfMessages;
|
||||||
|
this.nrOfElements = nrOfElements;
|
||||||
|
this.latch = latch;
|
||||||
|
Creator<Router> routerCreator = new Creator<Router>() {
|
||||||
|
public Router create() {
|
||||||
|
return new RoundRobinRouter();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
LinkedList<ActorRef> actors = new LinkedList<ActorRef>() {
|
||||||
|
{
|
||||||
|
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) {
|
// message handler
|
||||||
// this.nrOfMessages = nrOfMessages;
|
public void onReceive(Object message) {
|
||||||
// this.nrOfElements = nrOfElements;
|
|
||||||
// this.latch = latch;
|
|
||||||
|
|
||||||
// LinkedList<ActorRef> workers = new LinkedList<ActorRef>();
|
if (message instanceof Calculate) {
|
||||||
// for (int i = 0; i < nrOfWorkers; i++) {
|
|
||||||
// ActorRef worker = system.actorOf(Worker.class);
|
|
||||||
// workers.add(worker);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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
|
} else if (message instanceof Result) {
|
||||||
// public void onReceive(Object message) {
|
|
||||||
|
|
||||||
// if (message instanceof Calculate) {
|
// handle result from the worker
|
||||||
// // schedule work
|
Result result = (Result) message;
|
||||||
// for (int start = 0; start < nrOfMessages; start++) {
|
pi += result.getValue();
|
||||||
// router.tell(new Work(start, nrOfElements), getSelf());
|
nrOfResults += 1;
|
||||||
// }
|
if (nrOfResults == nrOfMessages) getSelf().stop();
|
||||||
|
|
||||||
// // send a PoisonPill to all workers telling them to shut down themselves
|
} else throw new IllegalArgumentException("Unknown message [" + message + "]");
|
||||||
// router.tell(new Broadcast(poisonPill()));
|
}
|
||||||
|
|
||||||
// // send a PoisonPill to the router, telling him to shut himself down
|
@Override
|
||||||
// router.tell(poisonPill());
|
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;
|
// ===== Run it =====
|
||||||
// pi += result.getValue();
|
// ==================
|
||||||
// nrOfResults += 1;
|
public void calculate(final int nrOfWorkers, final int nrOfElements, final int nrOfMessages)
|
||||||
// if (nrOfResults == nrOfMessages) getSelf().stop();
|
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
|
// create the master
|
||||||
// public void preStart() {
|
ActorRef master = system.actorOf(new UntypedActorFactory() {
|
||||||
// start = System.currentTimeMillis();
|
public UntypedActor create() {
|
||||||
// }
|
return new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// @Override
|
// start the calculation
|
||||||
// public void postStop() {
|
master.tell(new Calculate());
|
||||||
// // 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();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // ==================
|
// wait for master to shut down
|
||||||
// // ===== Run it =====
|
latch.await();
|
||||||
// // ==================
|
|
||||||
// public void calculate(final int nrOfWorkers, final int nrOfElements, final int nrOfMessages)
|
|
||||||
// throws Exception {
|
|
||||||
|
|
||||||
// // this latch is only plumbing to know when the calculation is completed
|
// Shut down the system
|
||||||
// final CountDownLatch latch = new CountDownLatch(1);
|
system.stop();
|
||||||
|
}
|
||||||
// // 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();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
|
|
@ -1,113 +1,114 @@
|
||||||
// /**
|
/**
|
||||||
// * Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
||||||
// */
|
*/
|
||||||
|
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 }
|
object Pi extends App {
|
||||||
// import Actor._
|
|
||||||
// import java.util.concurrent.CountDownLatch
|
|
||||||
// import akka.routing.Routing.Broadcast
|
|
||||||
// import akka.routing.{ RoutedProps, Routing }
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
// // ====================
|
case object Calculate extends PiMessage
|
||||||
// // ===== Messages =====
|
|
||||||
// // ====================
|
|
||||||
// sealed trait 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 {
|
||||||
|
|
||||||
// // ==================
|
// define the work
|
||||||
// // ===== Worker =====
|
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
|
||||||
// // ==================
|
var acc = 0.0
|
||||||
// class Worker extends Actor {
|
for (i ← start until (start + nrOfElements))
|
||||||
|
acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
// // define the work
|
def receive = {
|
||||||
// def calculatePiFor(start: Int, nrOfElements: Int): Double = {
|
case Work(start, nrOfElements) ⇒ sender ! Result(calculatePiFor(start, nrOfElements)) // perform the work
|
||||||
// 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
|
// ===== Master =====
|
||||||
// }
|
// ==================
|
||||||
// }
|
class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
||||||
|
extends Actor {
|
||||||
|
|
||||||
// // ==================
|
var pi: Double = _
|
||||||
// // ===== Master =====
|
var nrOfResults: Int = _
|
||||||
// // ==================
|
var start: Long = _
|
||||||
// class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, latch: CountDownLatch)
|
|
||||||
// extends Actor {
|
|
||||||
|
|
||||||
// var pi: Double = _
|
// create the workers
|
||||||
// var nrOfResults: Int = _
|
val workers = Vector.fill(nrOfWorkers)(system.actorOf[Worker])
|
||||||
// var start: Long = _
|
|
||||||
|
|
||||||
// // create the workers
|
// wrap them with a load-balancing router
|
||||||
// val workers = Vector.fill(nrOfWorkers)(system.actorOf[Worker])
|
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
|
// message handler
|
||||||
// val router = system.actorOf(RoutedProps().withRoundRobinRouter.withLocalConnections(workers), "pi")
|
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
|
// Stop this actor and all its supervised children
|
||||||
// def receive = {
|
if (nrOfResults == nrOfMessages) self.stop()
|
||||||
// case Calculate ⇒
|
}
|
||||||
// // schedule work
|
|
||||||
// for (i ← 0 until nrOfMessages) router ! Work(i * nrOfElements, nrOfElements)
|
|
||||||
|
|
||||||
// // send a PoisonPill to all workers telling them to shut down themselves
|
override def preStart() {
|
||||||
// router ! Broadcast(PoisonPill)
|
start = System.currentTimeMillis
|
||||||
|
}
|
||||||
|
|
||||||
// // send a PoisonPill to the router, telling him to shut himself down
|
override def postStop() {
|
||||||
// router ! PoisonPill
|
// 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) ⇒
|
object Master {
|
||||||
// // handle result from the worker
|
val impl = system.asInstanceOf[ActorSystemImpl]
|
||||||
// pi += value
|
}
|
||||||
// nrOfResults += 1
|
|
||||||
// if (nrOfResults == nrOfMessages) self.stop()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// override def preStart() {
|
// ==================
|
||||||
// start = System.currentTimeMillis
|
// ===== Run it =====
|
||||||
// }
|
// ==================
|
||||||
|
def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) {
|
||||||
|
|
||||||
// override def postStop() {
|
// this latch is only plumbing to know when the calculation is completed
|
||||||
// // tell the world that the calculation is complete
|
val latch = new CountDownLatch(1)
|
||||||
// println(
|
|
||||||
// "\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis"
|
|
||||||
// .format(pi, (System.currentTimeMillis - start)))
|
|
||||||
// latch.countDown()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // ==================
|
// create the master
|
||||||
// // ===== Run it =====
|
val master = system.actorOf(new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch))
|
||||||
// // ==================
|
|
||||||
// def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) {
|
|
||||||
|
|
||||||
// // this latch is only plumbing to know when the calculation is completed
|
// start the calculation
|
||||||
// val latch = new CountDownLatch(1)
|
master ! Calculate
|
||||||
|
|
||||||
// // create the master
|
// wait for master to shut down
|
||||||
// val master = system.actorOf(new Master(nrOfWorkers, nrOfMessages, nrOfElements, latch))
|
latch.await()
|
||||||
|
|
||||||
// // start the calculation
|
// Shut down the system
|
||||||
// master ! Calculate
|
system.stop()
|
||||||
|
}
|
||||||
// // wait for master to shut down
|
}
|
||||||
// latch.await()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -243,23 +243,31 @@ object AkkaBuild extends Build {
|
||||||
id = "akka-samples",
|
id = "akka-samples",
|
||||||
base = file("akka-samples"),
|
base = file("akka-samples"),
|
||||||
settings = parentSettings,
|
settings = parentSettings,
|
||||||
aggregate = Seq(fsmSample)
|
aggregate = Seq(antsSample, helloSample, osgiSample, fsmSample)
|
||||||
// aggregate = Seq(fsmSample, camelSample)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// lazy val antsSample = Project(
|
lazy val antsSample = Project(
|
||||||
// id = "akka-sample-ants",
|
id = "akka-sample-ants",
|
||||||
// base = file("akka-samples/akka-sample-ants"),
|
base = file("akka-samples/akka-sample-ants"),
|
||||||
// dependencies = Seq(stm),
|
dependencies = Seq(actor, stm),
|
||||||
// settings = defaultSettings
|
settings = defaultSettings
|
||||||
// )
|
)
|
||||||
|
|
||||||
// lazy val chatSample = Project(
|
lazy val helloSample = Project(
|
||||||
// id = "akka-sample-chat",
|
id = "akka-sample-hello",
|
||||||
// base = file("akka-samples/akka-sample-chat"),
|
base = file("akka-samples/akka-sample-hello"),
|
||||||
// dependencies = Seq(cluster),
|
dependencies = Seq(actor),
|
||||||
// settings = defaultSettings
|
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(
|
lazy val fsmSample = Project(
|
||||||
id = "akka-sample-fsm",
|
id = "akka-sample-fsm",
|
||||||
|
|
@ -268,6 +276,21 @@ object AkkaBuild extends Build {
|
||||||
settings = defaultSettings
|
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(
|
// lazy val camelSample = Project(
|
||||||
// id = "akka-sample-camel",
|
// id = "akka-sample-camel",
|
||||||
// base = file("akka-samples/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(
|
// lazy val remoteSample = Project(
|
||||||
// id = "akka-sample-remote",
|
// id = "akka-sample-remote",
|
||||||
// base = file("akka-samples/akka-sample-remote"),
|
// base = file("akka-samples/akka-sample-remote"),
|
||||||
|
|
@ -295,22 +311,24 @@ object AkkaBuild extends Build {
|
||||||
id = "akka-tutorials",
|
id = "akka-tutorials",
|
||||||
base = file("akka-tutorials"),
|
base = file("akka-tutorials"),
|
||||||
settings = parentSettings,
|
settings = parentSettings,
|
||||||
aggregate = Seq(firstTutorial, secondTutorial)
|
aggregate = Seq(firstTutorial)
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val firstTutorial = Project(
|
lazy val firstTutorial = Project(
|
||||||
id = "akka-tutorial-first",
|
id = "akka-tutorial-first",
|
||||||
base = file("akka-tutorials/akka-tutorial-first"),
|
base = file("akka-tutorials/akka-tutorial-first"),
|
||||||
dependencies = Seq(actor),
|
dependencies = Seq(actor, testkit),
|
||||||
settings = defaultSettings
|
settings = defaultSettings ++ Seq(
|
||||||
|
libraryDependencies ++= Dependencies.tutorials
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val secondTutorial = Project(
|
// lazy val secondTutorial = Project(
|
||||||
id = "akka-tutorial-second",
|
// id = "akka-tutorial-second",
|
||||||
base = file("akka-tutorials/akka-tutorial-second"),
|
// base = file("akka-tutorials/akka-tutorial-second"),
|
||||||
dependencies = Seq(actor),
|
// dependencies = Seq(actor),
|
||||||
settings = defaultSettings
|
// settings = defaultSettings
|
||||||
)
|
// )
|
||||||
|
|
||||||
lazy val docs = Project(
|
lazy val docs = Project(
|
||||||
id = "akka-docs",
|
id = "akka-docs",
|
||||||
|
|
@ -448,6 +466,10 @@ object Dependencies {
|
||||||
// val sampleCamel = Seq(camelCore, camelSpring, commonsCodec, Runtime.camelJms, Runtime.activemq, Runtime.springJms,
|
// val sampleCamel = Seq(camelCore, camelSpring, commonsCodec, Runtime.camelJms, Runtime.activemq, Runtime.springJms,
|
||||||
// Test.junit, Test.scalatest, Test.logback)
|
// Test.junit, Test.scalatest, Test.logback)
|
||||||
|
|
||||||
|
val sampleOsgi = Seq(osgi)
|
||||||
|
|
||||||
|
val tutorials = Seq(Test.scalatest, Test.junit)
|
||||||
|
|
||||||
val docs = Seq(Test.scalatest, Test.junit)
|
val docs = Seq(Test.scalatest, Test.junit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue