Updated samples and tutorial to Akka 2.0. Added projects to SBT project file. Fixes #1278

This commit is contained in:
Henrik Engstrom 2011-11-25 14:49:09 +01:00
parent c0d3c523e2
commit 823a68ac0f
33 changed files with 1291 additions and 1209 deletions

View file

@ -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
} }

View file

@ -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&#233;r</a> * @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/ */
class RoundRobinRouter extends BasicRouter { private[akka] class RoundRobinRouter extends BasicRouter {
private val state = new AtomicReference[RoundRobinState] private val state = new AtomicReference[RoundRobinState]

View file

@ -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 {

View file

@ -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() = {

View file

@ -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

View file

@ -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 }
} }
} }

View file

@ -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))
// }
// }
// }
//}

View file

@ -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)
// }
// })
// }
//}

View file

@ -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
//
// */
//}

View file

@ -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)
//
// */
//}

View file

@ -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)
// }
// }
//}
//

View file

@ -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"))
Thats 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"))
//
//
// Thats 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
// }
// }
//

View 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/

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"
}
}

View file

@ -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>

View 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/

View file

@ -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))
}

View file

@ -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
}

View file

@ -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!"
}
}

View file

@ -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
} }
} }

View file

@ -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
//}
//

View file

@ -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>

View file

@ -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")
)
)
}

View file

@ -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

View file

@ -1,3 +0,0 @@
import sbt._
class TutorialOneProject(info: ProjectInfo) extends DefaultProject(info) with AkkaProject

View file

@ -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"
}

View file

@ -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();
// }
// }

View file

@ -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()
// }
// }

View file

@ -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)
}
}
}

View file

@ -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)
} }