All Downloads are FREE. Search and download functionalities are using the official Maven repository.

geotrellis.process.actors.StepAggregator.scala Maven / Gradle / Ivy

The newest version!
package geotrellis.process.actors

import akka.actor._
import akka.routing._
import scala.concurrent.Await
import scala.concurrent.duration._

import geotrellis._
import geotrellis.process._


/** 
 * A StepAggregator is responsible for executing 
 * operations in a list of arguments that are returned
 * from a step in an Operation's execution. Each operation
 * is sent to the server for asynchronous execution.
 * Once all the operations are completed and the results
 * aggregated, a callback (the next step of the operation)
 * is executed and the results are handled by a ResultHandler.
 */
private[actors]
case class StepAggregator[T](serverContext:ServerContext, 
                             pos:Int, 
                             args:Args,
                             cb:Callback[T], 
                             client:ActorRef, 
                             history:History)
    extends Actor {

  val handler = new ResultHandler(serverContext,client,pos)

  // These results won't (necessarily) share any type info with each other, so
  // we have to use Any as the least-upper type bound :(
  val results = Array.fill[Option[InternalOperationResult[Any]]](args.length)(None)

  // Just after starting the actor, we need to dispatch out the child
  // operations to be run. If none of those existed, we should run the
  // callback and be done.
  override def preStart {
    for (i <- 0 until args.length) {
      args(i) match {
        case lit:Literal[_] =>
          val v = lit.value
          results(i) = Some(Complete(v,History.literal(v,serverContext.externalId)))
        case op:Operation[_] =>
          serverContext.serverRef ! RunOperation(op, i, self)
        case value =>
          results(i) = Some(Inlined(value))
      }
    }

    if (isDone) { 
      finishCallback()
      context.stop(self)
    }
  }

  // This should create a list of all the (non-trivial) child histories we
  // have. This leaves out inlined arguments, who don't have history in any
  // real sense (e.g. they were complete when we received them).
  def childHistories = 
    results.toList.flatMap {
      case Some(Complete(_, t)) => Some(t)
      case Some(Error(_, t)) => Some(t)
      case Some(Inlined(_)) => None
      case None => None
    }

  // If any entry in the results array is null, we're not done.
  def isDone = results.find(_ == None).isEmpty

  def error:Option[Error] = 
    results.flatten
           .filter { case err:Error => true; case _ => false }
           .headOption
           .map { err => err.asInstanceOf[Error] }

  // Create a list of the actual values of our children.
  def getValues = results.toList.map {
    case Some(Complete(value, _)) => value
    case Some(Inlined(value)) => value
    case r => sys.error("found unexpected result (some(error)) ") 
  }

  // This is called when we have heard back from all our sub-operations and
  // are ready to begin evaluation. After this point we will terminate and not
  // receive any more messages.
  def finishCallback() {
    try {
      handler.handleResult(cb(getValues),history.withStep(childHistories))
    } catch {
      case e:Throwable => {
        val error = StepError.fromException(e)
        System.err.println(s"Operation failed, with exception: $e\n\nStack trace:${error.trace}\n\n")
        handler.handleResult(error,history.withStep(childHistories))
      }
    }
    context.stop(self)
  }

  // Actor event loop
  def receive = {
    case PositionedResult(childResult,  pos) => {
      results(pos) = Some(childResult)
      if (isDone) {
        error match {
          case Some(Error(msg,trace)) =>
            val se = StepError(msg, trace)
            handler.handleResult(se,history.withStep(childHistories))
          case None =>
            finishCallback()
            context.stop(self)
        }
      }
    }

    case g => sys.error(s"${this.getClass.getSimpleName} got unknown message: %s" format g)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy