2010-03-10 22:38:52 +01:00
|
|
|
package se.scalablesolutions.akka.patterns
|
2010-02-13 21:45:35 +01:00
|
|
|
|
2010-05-02 10:50:45 +02:00
|
|
|
import se.scalablesolutions.akka.actor.{Actor, ActorID}
|
|
|
|
|
import se.scalablesolutions.akka.actor.Actor._
|
2010-02-13 21:45:35 +01:00
|
|
|
|
|
|
|
|
object Patterns {
|
2010-03-04 19:02:23 +01:00
|
|
|
type PF[A, B] = PartialFunction[A, B]
|
2010-02-13 21:45:35 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a new PartialFunction whose isDefinedAt is a combination
|
|
|
|
|
* of the two parameters, and whose apply is first to call filter.apply and then filtered.apply
|
|
|
|
|
*/
|
2010-03-04 19:02:23 +01:00
|
|
|
def filter[A, B](filter: PF[A, Unit], filtered: PF[A, B]): PF[A, B] = {
|
|
|
|
|
case a: A if filtered.isDefinedAt(a) && filter.isDefinedAt(a) =>
|
2010-02-13 21:45:35 +01:00
|
|
|
filter(a)
|
|
|
|
|
filtered(a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Interceptor is a filter(x,y) where x.isDefinedAt is considered to be always true
|
|
|
|
|
*/
|
2010-03-17 17:48:46 +01:00
|
|
|
def intercept[A, B](interceptor: (A) => Unit, interceptee: PF[A, B]): PF[A, B] =
|
|
|
|
|
filter({case a if a.isInstanceOf[A] => interceptor(a)}, interceptee)
|
2010-03-04 19:02:23 +01:00
|
|
|
|
2010-02-13 21:45:35 +01:00
|
|
|
//FIXME 2.8, use default params with CyclicIterator
|
2010-05-02 10:50:45 +02:00
|
|
|
def loadBalancerActor(actors: => InfiniteIterator[ActorID]): ActorID = newActor(() => new Actor with LoadBalancer {
|
2010-02-13 21:45:35 +01:00
|
|
|
val seq = actors
|
2010-05-02 10:50:45 +02:00
|
|
|
})
|
2010-02-13 21:45:35 +01:00
|
|
|
|
2010-05-02 10:50:45 +02:00
|
|
|
def dispatcherActor(routing: PF[Any, ActorID], msgTransformer: (Any) => Any): ActorID = newActor(() => new Actor with Dispatcher {
|
2010-03-04 19:02:23 +01:00
|
|
|
override def transform(msg: Any) = msgTransformer(msg)
|
2010-02-13 21:45:35 +01:00
|
|
|
def routes = routing
|
2010-05-02 10:50:45 +02:00
|
|
|
})
|
2010-03-04 19:02:23 +01:00
|
|
|
|
2010-05-02 10:50:45 +02:00
|
|
|
def dispatcherActor(routing: PF[Any, ActorID]): ActorID = newActor(() => new Actor with Dispatcher {
|
2010-03-04 19:02:23 +01:00
|
|
|
def routes = routing
|
2010-05-02 10:50:45 +02:00
|
|
|
})
|
2010-02-13 21:45:35 +01:00
|
|
|
|
2010-05-02 10:50:45 +02:00
|
|
|
def loggerActor(actorToLog: ActorID, logger: (Any) => Unit): ActorID =
|
2010-03-17 17:48:46 +01:00
|
|
|
dispatcherActor({case _ => actorToLog}, logger)
|
2010-02-13 21:45:35 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-17 17:48:46 +01:00
|
|
|
trait Dispatcher { self: Actor =>
|
2010-02-13 21:45:35 +01:00
|
|
|
|
2010-03-04 19:02:23 +01:00
|
|
|
protected def transform(msg: Any): Any = msg
|
|
|
|
|
|
2010-05-02 10:50:45 +02:00
|
|
|
protected def routes: PartialFunction[Any, ActorID]
|
2010-03-04 19:02:23 +01:00
|
|
|
|
|
|
|
|
protected def dispatch: PartialFunction[Any, Unit] = {
|
2010-03-17 17:48:46 +01:00
|
|
|
case a if routes.isDefinedAt(a) =>
|
2010-04-06 22:37:34 +02:00
|
|
|
if (self.replyTo.isDefined) routes(a) forward transform(a)
|
2010-03-30 23:58:50 +02:00
|
|
|
else routes(a) ! transform(a)
|
2010-02-13 21:45:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def receive = dispatch
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-17 17:48:46 +01:00
|
|
|
trait LoadBalancer extends Dispatcher { self: Actor =>
|
2010-05-02 10:50:45 +02:00
|
|
|
protected def seq: InfiniteIterator[ActorID]
|
2010-02-13 21:45:35 +01:00
|
|
|
|
2010-03-17 17:48:46 +01:00
|
|
|
protected def routes = { case x if seq.hasNext => seq.next }
|
2010-02-13 21:45:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trait InfiniteIterator[T] extends Iterator[T]
|
|
|
|
|
|
2010-03-04 19:02:23 +01:00
|
|
|
class CyclicIterator[T](items: List[T]) extends InfiniteIterator[T] {
|
|
|
|
|
@volatile private[this] var current: List[T] = items
|
|
|
|
|
|
2010-02-13 21:45:35 +01:00
|
|
|
def hasNext = items != Nil
|
2010-03-04 19:02:23 +01:00
|
|
|
|
2010-02-13 21:45:35 +01:00
|
|
|
def next = {
|
2010-03-04 19:02:23 +01:00
|
|
|
val nc = if (current == Nil) items else current
|
2010-02-13 21:45:35 +01:00
|
|
|
current = nc.tail
|
|
|
|
|
nc.head
|
|
|
|
|
}
|
2010-03-17 22:10:49 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-02 10:50:45 +02:00
|
|
|
class SmallestMailboxFirstIterator(items : List[ActorID]) extends InfiniteIterator[ActorID] {
|
2010-03-17 22:10:49 +01:00
|
|
|
def hasNext = items != Nil
|
|
|
|
|
|
|
|
|
|
def next = {
|
2010-05-02 10:50:45 +02:00
|
|
|
def actorWithSmallestMailbox(a1: ActorID, a2: ActorID) = {
|
2010-03-17 22:10:49 +01:00
|
|
|
if (a1.mailboxSize < a2.mailboxSize) a1 else a2
|
|
|
|
|
}
|
|
|
|
|
items.reduceLeft((actor1, actor2) => actorWithSmallestMailbox(actor1,actor2))
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-24 14:56:50 +02:00
|
|
|
|
|
|
|
|
sealed trait ListenerMessage
|
2010-05-02 10:50:45 +02:00
|
|
|
case class Listen(listener : ActorID) extends ListenerMessage
|
|
|
|
|
case class Deafen(listener : ActorID) extends ListenerMessage
|
|
|
|
|
case class WithListeners(f : Set[ActorID] => Unit) extends ListenerMessage
|
2010-04-24 14:56:50 +02:00
|
|
|
|
|
|
|
|
trait Listeners { self : Actor =>
|
|
|
|
|
import se.scalablesolutions.akka.actor.Agent
|
2010-05-02 10:50:45 +02:00
|
|
|
private lazy val listeners = Agent(Set[ActorID]())
|
2010-04-24 14:56:50 +02:00
|
|
|
|
|
|
|
|
protected def listenerManagement : PartialFunction[Any,Unit] = {
|
|
|
|
|
case Listen(l) => listeners( _ + l)
|
|
|
|
|
case Deafen(l) => listeners( _ - l )
|
|
|
|
|
case WithListeners(f) => listeners foreach f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected def gossip(msg : Any) = listeners foreach ( _ foreach ( _ ! msg ) )
|
|
|
|
|
}
|