diff --git a/akka-patterns/src/main/scala/Patterns.scala b/akka-patterns/src/main/scala/Patterns.scala index fc50292676..d8a49c74e3 100644 --- a/akka-patterns/src/main/scala/Patterns.scala +++ b/akka-patterns/src/main/scala/Patterns.scala @@ -85,3 +85,21 @@ class SmallestMailboxFirstIterator(items : List[Actor]) extends InfiniteIterator items.reduceLeft((actor1, actor2) => actorWithSmallestMailbox(actor1,actor2)) } } + +sealed trait ListenerMessage +case class Listen(listener : Actor) extends ListenerMessage +case class Deafen(listener : Actor) extends ListenerMessage +case class WithListeners(f : Set[Actor] => Unit) extends ListenerMessage + +trait Listeners { self : Actor => + import se.scalablesolutions.akka.actor.Agent + private lazy val listeners = Agent(Set[Actor]()) + + 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 ) ) +} \ No newline at end of file diff --git a/akka-patterns/src/test/scala/ActorPatternsTest.scala b/akka-patterns/src/test/scala/ActorPatternsTest.scala index 0ce999add0..2235b1a1a7 100644 --- a/akka-patterns/src/test/scala/ActorPatternsTest.scala +++ b/akka-patterns/src/test/scala/ActorPatternsTest.scala @@ -90,6 +90,44 @@ class ActorPatternsTest extends junit.framework.TestCase with Suite with MustMat } } }) + + @Test def testListener = verify(new TestActor { + import java.util.concurrent.{ CountDownLatch, TimeUnit } + + def test = { + val latch = new CountDownLatch(2) + val num = new AtomicInteger(0) + val i = new Actor with Listeners { + def receive = listenerManagement orElse { + case "foo" => gossip("bar") + } + } + i.start + + def newListener = actor { + case "bar" => + num.incrementAndGet + latch.countDown + } + + val a1 = newListener + val a2 = newListener + val a3 = newListener + + handle(i,a1,a2,a3) { + i ! Listen(a1) + i ! Listen(a2) + i ! Listen(a3) + i ! Deafen(a3) + + i ! "foo" + + val done = latch.await(5,TimeUnit.SECONDS) + done must be (true) + num.get must be (2) + } + } + }); }