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

loci.registry.Bindings.scala Maven / Gradle / Ivy

The newest version!
package loci
package registry

import transmitter._

import java.util.concurrent.ConcurrentHashMap

import scala.util.{Failure, Try}

class Bindings[A <: AbstractionRef](
    request: (A, MessageBuffer) => Unit,
    respond: (A, Try[MessageBuffer]) => Unit) {

  private val bindings = new ConcurrentHashMap[
    String, (MessageBuffer, A) => Try[MessageBuffer]]

  private val responseHandlers = new ConcurrentHashMap[
    Channel, Notice.Steady.Source[Try[MessageBuffer]]]

  def bind[T, R](binding: Binding[T, R])(function: RemoteRef => T): Unit =
    bindings.put(binding.name, binding.dispatch(function, _, _))

  def lookup[T, R](binding: Binding[T, R], createAbstraction: () => A): R =
    binding.call(createAbstraction) { (message, abstraction) =>
      val channel = abstraction.channel
      val response = Notice.Steady[Try[MessageBuffer]]

      responseHandlers.put(channel, response)

      if (!abstraction.remote.connected)
        channelsClosed()

      logging.trace(s"sending remote access for $abstraction")

      request(abstraction, message)
      response.notice
    }

  def processRequest(
      message: MessageBuffer, name: String, abstraction: A): Unit = {
    logging.trace(s"handling remote access for $abstraction")

    val value = bindings get name match {
      case null =>
        Failure(new RemoteAccessException(s"request for $abstraction could not be dispatched"))
      case dispatch =>
        dispatch(message, abstraction)
    }

    value.failed foreach { exception =>
      logging.warn("local exception upon remote access propagated to remote instance", exception)
    }

    logging.trace(s"sending remote access response for $abstraction")

    respond(abstraction, value)
  }

  def processResponse(
      message: Try[MessageBuffer], name: String, abstraction: A): Unit =
    responseHandlers.remove(abstraction.channel) match {
      case null =>
        logging.warn(s"unprocessed message for $abstraction [no handler]: $message")
      case response =>
        response.set(message)
    }

  def channelsClosed(): Unit = {
    val iterator = responseHandlers.entrySet.iterator
    while (iterator.hasNext) {
      val entry = iterator.next()
      if (!entry.getKey.open) {
        entry.getValue.trySet(Failure(new RemoteAccessException(RemoteAccessException.RemoteDisconnected)))
        iterator.remove()
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy