Skip to content

Commit

Permalink
Improved completion handling but still not 100%
Browse files Browse the repository at this point in the history
  • Loading branch information
mslinn committed Nov 22, 2011
1 parent bdff9a7 commit 1d13a0a
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 22 deletions.
39 changes: 29 additions & 10 deletions src/main/scala/net/interdoodle/hanuman/HanumanService.scala
Expand Up @@ -13,10 +13,11 @@ import blueeyes.core.service.{HttpService, HttpServiceContext}
import blueeyes.json.JsonAST._

import java.util.UUID
import net.interdoodle.hanuman.message.SimulationStatus
import message.{SimulationComplete, GetSimulationStatus, TextMatch, SimulationStatuses}
import net.interdoodle.hanuman.domain.Hanuman
import net.interdoodle.hanuman.domain.Hanuman.{Simulations, TextMatchMap}
import net.interdoodle.hanuman.domain.Hanuman.{Simulations, TextMatchMap, TextMatchMapImmutable}
import net.lag.logging.Logger
import akka.event.EventHandler


/**
Expand All @@ -31,7 +32,7 @@ trait HanumanService extends BlueEyesServiceBuilder
private val simulations:Simulations = new Simulations()

/** Contains simulationID->Option[WorkVisorRef] map */
private var simulationStatus = new SimulationStatus(false, simulations)
private var simulationStatus = new SimulationStatuses(false, simulations)
private val simulationStatusRef = new Ref(simulationStatus)

private val contentUrl = System.getenv("CONTENT_URL")
Expand Down Expand Up @@ -96,6 +97,18 @@ trait HanumanService extends BlueEyesServiceBuilder
hanumanRefOption = Some(Actor.actorOf(
new Hanuman(simulationID, Configuration().workCellsPerVisor, Configuration().maxTicks, document, simulationStatusRef)))

/* This is one way to detect completion; it is redundant because Hanuman sets a completion flag in
simulationResults but I left it as an example of how a non-actor can retrieve results from an actor.
The handler could also shut down all actors if desired. */
EventHandler.addListener(Actor.actorOf(new Actor {
self.dispatcher = EventHandler.EventHandlerDispatcher

def receive = {
case SimulationComplete(simulationID) =>
println("Notify client that simulation " + simulationID + " is done")
}
}))

Future.sync(HttpResponse(content = Some(JObject(List(JField("id", simulationID))))))
} else {
val msg = "The only operation that can be without a simulationID is newSimulation. You specified '" + operation + "'"
Expand Down Expand Up @@ -147,13 +160,19 @@ trait HanumanService extends BlueEyesServiceBuilder
command + " is an unknown command"
}

/** @return status of simulation with given simulationID */
/** @return status of simulation with given simulationID as JSON */
private def simulationStatusAsJson(simulationID:String) = {
val simulation = simulationStatusRef.get.simulations(simulationID)
val result = JArray({
for (kv <- simulation) // Iterable[TextMatch]
yield kv._2.decompose
}.toList)
JObject(JField("result", result) :: Nil)
val resultOption = (hanumanRefOption.get ? GetSimulationStatus(simulationID)).await.get
resultOption match {
case Some(textMatchMap) =>
val result = JArray({
for (kv <- textMatchMap.asInstanceOf[TextMatchMap])
yield kv._2.decompose
}.toList)
JObject(JField("result", result) :: Nil)

case None => // time out
JString("result")
}
}
}
19 changes: 11 additions & 8 deletions src/main/scala/net/interdoodle/hanuman/domain/Hanuman.scala
Expand Up @@ -4,7 +4,7 @@ import akka.actor.Actor
import akka.event.EventHandler
import akka.stm.Ref
import collection.mutable.HashMap
import net.interdoodle.hanuman.domain.Hanuman.{TextMatchMap, TextMatchMapRef}
import net.interdoodle.hanuman.domain.Hanuman.{TextMatchMap, TextMatchMapImmutable, TextMatchMapRef}
import net.interdoodle.hanuman.message._
import scala.collection.JavaConversions._
import akka.actor.Uuid
Expand All @@ -16,39 +16,41 @@ class Hanuman(val simulationID:String,
val workCellsPerVisor:Int,
val maxTicks:Int,
val document:String,
val simulationStatusRef:Ref[SimulationStatus]) extends Actor {
val simulationStatusRef:Ref[SimulationStatuses]) extends Actor {
val textMatchMapRef = new TextMatchMapRef()
var textMatchMap = new TextMatchMap()
textMatchMapRef.set(textMatchMap)
var simulationStatus = simulationStatusRef.get
simulationStatus.putSimulation(simulationID, textMatchMap)


override def postStop() {
}

override def preStart() {
createWorkVisor()
}

def receive = {
case GetSimulationStatus(simulationID) =>
EventHandler.debug(this, "Hanuman returning TextMatchMap for simulation " + simulationID)
self.channel ! simulationStatus.simulations.get(simulationID)

case DocumentMatch(workUnitRef, startIndex) =>
simulationStatusRef.set(simulationStatus)
EventHandler.debug(this, "Hanuman is done")
simulationStatusRef.set(simulationStatus) //FIXME return result

case "stop" =>
EventHandler.debug(this, "Hanuman received a stop message")
for (workVisorRef <- self.linkedActors.values())
workVisorRef ! "stop"

case "stopped" =>
case SimulationComplete(simulationID) =>
EventHandler.debug(this, "Hanuman received a 'stopped' message from a WorkVisor")
self.unlink(self.sender.get)
if (self.linkedActors.size()==0) { // WorkVisors are all stopped
//self.stop() // Keep Hanuman running
val ss = new SimulationStatus(true, simulationStatusRef.get.simulations)
val ss = new SimulationStatuses(true, simulationStatusRef.get.simulations)
simulationStatusRef.set(ss)
}
EventHandler.notify(SimulationComplete(simulationID))

case _ =>
EventHandler.info(this, "Hanuman received an unknown message")
Expand All @@ -66,5 +68,6 @@ object Hanuman {
/** map of simulation sessionID to TextMatch map */
type Simulations = HashMap[String, TextMatchMap]
type TextMatchMap = HashMap[Uuid, TextMatch]
type TextMatchMapImmutable = scala.collection.immutable.HashMap[Uuid, TextMatch]
type TextMatchMapRef = Ref[TextMatchMap]
}
Expand Up @@ -69,7 +69,7 @@ class WorkVisor(val simulationID:String,
self.unlink(workCellActorRef)
}
EventHandler.debug(this, "All WorkCells have stopped")
self.supervisor ! "stopped"
self.supervisor ! SimulationComplete(simulationID)
}
/** Cause each Monkey to generate a page of semi-random text */
private def tick {
Expand Down
@@ -0,0 +1,5 @@
package net.interdoodle.hanuman.message

/** @author Mike Slinn */

case class GetSimulationStatus(simulationID:String)
@@ -0,0 +1,6 @@
package net.interdoodle.hanuman.message

/**
* @author Mike Slinn */

case class SimulationComplete(sessionID:String)
Expand Up @@ -5,7 +5,7 @@ import net.interdoodle.hanuman.domain.Hanuman.{Simulations, TextMatchMap}

/**
* @author Mike Slinn */
case class SimulationStatus(complete:Boolean, simulations:Simulations) {
case class SimulationStatuses(complete:Boolean, simulations:Simulations) {
def getSimulation(simulationID:String) = {
simulations.getOrElse(simulationID, None)
}
Expand Down
Expand Up @@ -3,7 +3,7 @@ package net.interdoodle.hanuman.domain
import akka.actor.{Actor, Uuid}
import akka.stm.Ref
import net.interdoodle.hanuman.domain.Hanuman.{Simulations, TextMatchMap, TextMatchMapRef}
import net.interdoodle.hanuman.message.{SimulationStatus, TextMatch}
import net.interdoodle.hanuman.message.{SimulationStatuses, TextMatch}
import org.scalatest.FunSuite


Expand All @@ -20,7 +20,7 @@ class WorkVisorSuite extends FunSuite {
val textMatchMapRef = new TextMatchMapRef()
textMatchMapRef.set(textMatchMap)
val simulations:Simulations = new Simulations()
val simulationStatusRef = Ref(new SimulationStatus(false, simulations))
val simulationStatusRef = Ref(new SimulationStatuses(false, simulations))

/** Rough character frequency approximation */
val document = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"*5 +
Expand Down

0 comments on commit 1d13a0a

Please sign in to comment.