2009-05-25 14:48:43 +02:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2009 Scalable Solutions.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
2009-05-25 15:18:18 +02:00
|
|
|
* Implements the Reactor pattern as defined in: [http://www.cs.wustl.edu/~schmidt/PDF/reactor-siemens.pdf].
|
|
|
|
|
* See also this article: [http://today.java.net/cs/user/print/a/350].
|
|
|
|
|
*
|
2009-05-25 14:48:43 +02:00
|
|
|
* Based on code from the actorom actor framework by Sergio Bossa [http://code.google.com/p/actorom/].
|
|
|
|
|
*/
|
|
|
|
|
package se.scalablesolutions.akka.kernel.reactor
|
|
|
|
|
|
2009-06-24 15:12:47 +02:00
|
|
|
import java.util.concurrent.atomic.AtomicInteger
|
|
|
|
|
import java.util.concurrent.ThreadFactory
|
2009-05-25 14:48:43 +02:00
|
|
|
import java.util.{LinkedList, Queue}
|
2009-06-24 15:12:47 +02:00
|
|
|
import kernel.util.{Logging, HashCode}
|
2009-06-05 22:08:53 +02:00
|
|
|
trait MessageHandler {
|
|
|
|
|
def handle(message: MessageHandle)
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-25 14:48:43 +02:00
|
|
|
trait MessageDispatcher {
|
2009-06-10 20:04:33 +02:00
|
|
|
def messageQueue: MessageQueue
|
2009-05-25 14:48:43 +02:00
|
|
|
def registerHandler(key: AnyRef, handler: MessageHandler)
|
|
|
|
|
def unregisterHandler(key: AnyRef)
|
2009-06-05 22:08:53 +02:00
|
|
|
def start
|
2009-05-25 14:48:43 +02:00
|
|
|
def shutdown
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trait MessageDemultiplexer {
|
|
|
|
|
def select
|
|
|
|
|
def acquireSelectedQueue: Queue[MessageHandle]
|
|
|
|
|
def releaseSelectedQueue
|
|
|
|
|
def wakeUp
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-05 22:08:53 +02:00
|
|
|
class MessageHandle(val sender: AnyRef, val message: AnyRef, val future: CompletableFutureResult) {
|
2009-05-25 14:48:43 +02:00
|
|
|
|
2009-05-25 15:18:18 +02:00
|
|
|
override def hashCode(): Int = {
|
|
|
|
|
var result = HashCode.SEED
|
2009-06-05 22:08:53 +02:00
|
|
|
result = HashCode.hash(result, sender)
|
2009-05-25 15:18:18 +02:00
|
|
|
result = HashCode.hash(result, message)
|
|
|
|
|
result = HashCode.hash(result, future)
|
|
|
|
|
result
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
2009-05-25 15:18:18 +02:00
|
|
|
|
|
|
|
|
override def equals(that: Any): Boolean =
|
|
|
|
|
that != null &&
|
|
|
|
|
that.isInstanceOf[MessageHandle] &&
|
2009-06-05 22:08:53 +02:00
|
|
|
that.asInstanceOf[MessageHandle].sender == sender &&
|
2009-05-25 15:18:18 +02:00
|
|
|
that.asInstanceOf[MessageHandle].message == message &&
|
|
|
|
|
that.asInstanceOf[MessageHandle].future == future
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class MessageQueue {
|
2009-06-21 14:08:43 +02:00
|
|
|
private[kernel] val queue: Queue[MessageHandle] = new LinkedList[MessageHandle]
|
2009-05-25 14:48:43 +02:00
|
|
|
@volatile private var interrupted = false
|
|
|
|
|
|
2009-06-05 22:08:53 +02:00
|
|
|
def append(handle: MessageHandle) = queue.synchronized {
|
|
|
|
|
queue.offer(handle)
|
|
|
|
|
queue.notifyAll
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
|
2009-06-05 22:08:53 +02:00
|
|
|
def prepend(handle: MessageHandle) = queue.synchronized {
|
|
|
|
|
queue.add(handle)
|
|
|
|
|
queue.notifyAll
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def read(destination: Queue[MessageHandle]) = queue.synchronized {
|
|
|
|
|
while (queue.isEmpty && !interrupted) queue.wait
|
|
|
|
|
if (!interrupted) while (!queue.isEmpty) destination.offer(queue.remove)
|
|
|
|
|
else interrupted = false
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
|
2009-06-05 22:08:53 +02:00
|
|
|
def interrupt = queue.synchronized {
|
2009-05-25 14:48:43 +02:00
|
|
|
interrupted = true
|
2009-06-05 22:08:53 +02:00
|
|
|
queue.notifyAll
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-06-24 15:12:47 +02:00
|
|
|
|
|
|
|
|
class MonitorableThreadFactory(val name: String) extends ThreadFactory {
|
|
|
|
|
def newThread(runnable: Runnable) =
|
|
|
|
|
//new MonitorableThread(runnable, name)
|
|
|
|
|
new Thread(runnable)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object MonitorableThread {
|
|
|
|
|
val DEFAULT_NAME = "MonitorableThread"
|
|
|
|
|
val created = new AtomicInteger
|
|
|
|
|
val alive = new AtomicInteger
|
|
|
|
|
@volatile val debugLifecycle = false
|
|
|
|
|
}
|
|
|
|
|
class MonitorableThread(runnable: Runnable, name: String)
|
|
|
|
|
extends Thread(runnable, name + "-" + MonitorableThread.created.incrementAndGet) {//with Logging {
|
|
|
|
|
setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
|
|
|
|
def uncaughtException(thread: Thread, cause: Throwable) = {} //log.error("UNCAUGHT in thread [%s] cause [%s]", thread.getName, cause)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
override def run = {
|
|
|
|
|
val debug = MonitorableThread.debugLifecycle
|
|
|
|
|
//if (debug) log.debug("Created %s", getName)
|
|
|
|
|
try {
|
|
|
|
|
MonitorableThread.alive.incrementAndGet
|
|
|
|
|
super.run
|
|
|
|
|
} finally {
|
|
|
|
|
MonitorableThread.alive.decrementAndGet
|
|
|
|
|
//if (debug) log.debug("Exiting %s", getName)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|