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

com.socrata.future.Promise.scala Maven / Gradle / Ivy

package com.socrata.future

import java.util.concurrent.CountDownLatch

/** An object that represents the promise to produce a result
 * at some point in the future. */
class Promise[A](implicit executionContext: ExecutionContext) { self =>
  private var listeners: List[Either[Throwable, A] => _] = Nil
  private var result: Either[Throwable, A] = _

  /** Break the promise by setting the result to an exception to be
   * re-thrown when the promise is demanded.
   *
   * @throws IllegalStateException if the promise has already been fulfilled or broken. */
  def break(err: Throwable) { setResult(Left(err)) }

  /**Fulfill the promise by setting the result to the given value.
   *
   * @throws IllegalStateException if the promise has already been fulfilled or broken. */
  def fulfill(result: A) { setResult(Right(result)) }

  private def setResult(r: Either[Throwable, A]) {
    val wereWaiting = synchronized {
      if(result != null) throw new IllegalStateException("Promise has already been fulfilled or broken.")
      result = r
      val go = listeners
      listeners = Nil
      go
    }
    wereWaiting.foreach(executeOnResult)
  }

  private def executeOnResult(listener: Either[Throwable, A] => _) {
    executionContext.execute {
      try {
        listener(result)
      } catch {
        case t: Throwable =>
          // FIXME something more than this
          t.printStackTrace()
      }
    }
  }

  /** A [[com.socrata.future.Future]] which can be used to access the result of this promise. */
  val future: Future[A] = new Future[A] {
    def onComplete[B](res: Either[Throwable, A] => B) {
      val goNow = self.synchronized {
        if(self.result == null) {
          listeners ::= res
          false
        } else {
          true
        }
      }
      if(goNow) executeOnResult(res)
    }

    def result(): Option[A] = {
      val r = synchronized {
        if(self.result == null) return None
        self.result
      }
      r match {
        case Left(t) => throw t
        case Right(x) => Some(x)
      }
    }

    def await() {
      val join = new CountDownLatch(1)
      onComplete { _ => join.countDown() }
      join.await()
    }

    def executionContext = Promise.this.executionContext
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy