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

com.twitter.finagle.netty3.ChannelFuture.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finagle.netty3

import com.twitter.util.Promise
import org.jboss.netty.channel._

/**
 * A ChannelFuture that doesn't need to have a channel on creation.
 */
private[finagle] class LatentChannelFuture extends DefaultChannelFuture(null, false) {
  @volatile private var channel: Channel = _

  def setChannel(c: Channel) { channel = c }
  override def getChannel() = channel
}

private[finagle] sealed abstract class State
private[finagle] case object Cancelled extends State
private[finagle] case class Ok(channel: Channel) extends State
private[finagle] case class Error(cause: Throwable) extends State

private[finagle] class CancelledException extends Exception

object RichChannelFuture {

  private def state(channelFuture: ChannelFuture): State = {
    if (channelFuture.isSuccess)
      Ok(channelFuture.getChannel)
    else if (channelFuture.isCancelled)
      Cancelled
    else
      Error(channelFuture.getCause)
  }
}

// TODO: decide what to do about cancellation here.
private[finagle] class RichChannelFuture(val self: ChannelFuture) {
  def apply(f: State => Unit) {
    self.addListener(new ChannelFutureListener {
      def operationComplete(future: ChannelFuture) {
        f(RichChannelFuture.state(future))
      }
    })
  }

  def update(state: State) {
    state match {
      case Ok(channel)  => self.setSuccess()
      case Error(cause) => self.setFailure(cause)
      case Cancelled    => self.cancel()
    }
  }

  def state: State = RichChannelFuture.state(self)

  def proxyTo(other: ChannelFuture) {
    this {
      case Ok(channel)  => other.setSuccess()
      case Error(cause) => other.setFailure(cause)
      case Cancelled    => other.cancel()
    }
  }

  /**
   * the ChannelFuture forms a Monad.
   */
  def flatMap(f: Channel => ChannelFuture): ChannelFuture = {
    val future = new LatentChannelFuture

    // TODO: cancellation.

    this {
      case Ok(channel) =>
        val nextFuture = f(channel)
        nextFuture.addListener(new ChannelFutureListener {
          def operationComplete(nextFuture: ChannelFuture) {
            future.setChannel(nextFuture.getChannel)
            if (nextFuture.isSuccess)
              future.setSuccess()
            else
              future.setFailure(nextFuture.getCause)
          }
        })
      case Error(throwable) =>
        future.setFailure(throwable)
      case Cancelled =>
        future.cancel()
    }

    future
  }

  def map[T](f: Channel => Channel) = {
    val future = new LatentChannelFuture
    future.setChannel(self.getChannel)

    this {
      case Ok(channel) =>
        future.setChannel(f(channel))
        future.setSuccess()
      case Error(cause) =>
        future.setFailure(cause)
      case Cancelled =>
        future.cancel()
    }

    future
  }

  def foreach[T](f: Channel => T) {
    this {
      case Ok(channel) => f(channel)
      case _ => ()
    }
  }

  def onSuccess(f: => Unit) = {
    foreach { _ => f }
    self
  }

  def onError(f: Throwable => Unit) = {
    this {
      case Error(cause) => f(cause)
      case _ => ()
    }
    self
  }

  def onSuccessOrFailure(f: => Unit) {
    this {
      case Cancelled => ()
      case _ => f
    }
  }

  def onCancellation(f: => Unit) {
    this {
      case Cancelled => f
      case _ => ()
    }
  }

  // tbd
  // def always(f: Channel => Unit) =
  //   this { case state: State => f(self.getChannel) }

  def orElse(other: RichChannelFuture): ChannelFuture = {
    val combined = new LatentChannelFuture

    this.proxyTo(combined)
    other.proxyTo(combined)

    combined
  }

  def andThen(next: ChannelFuture): ChannelFuture = flatMap { _ => next }

  def close() {
    self.addListener(ChannelFutureListener.CLOSE)
  }

  def toTwitterFuture = {
    val result = new Promise[Unit]
    apply {
      case Ok(_)     => result.setDone()
      case Cancelled => result.setException(new CancelledException)
      case Error(e)  => result.setException(e)
    }
    result
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy