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

com.coiney.akka.rabbit.RabbitSystem.scala Maven / Gradle / Ivy

package com.coiney.akka.rabbit

import java.util.concurrent.CountDownLatch

import akka.actor.{Actor, Props, ActorRef, ActorRefFactory}
import akka.pattern.ask
import com.typesafe.config.{ConfigFactory, Config}

import com.coiney.akka.pattern.Observable
import com.coiney.akka.rabbit.actors._
import com.coiney.akka.rabbit.protocol.{RabbitRPCProcessor, ConsumeQueue, RabbitRequest}

import scala.concurrent.Await
import scala.concurrent.duration._


object RabbitSystem {

  def apply()(implicit actorRefFactory: ActorRefFactory): RabbitSystem =
    apply(None, None)(actorRefFactory)

  def apply(config: Config)(implicit actorRefFactory: ActorRefFactory): RabbitSystem =
    apply(Option(config), None)(actorRefFactory)

  def apply(config: Config, classLoader: ClassLoader)(implicit actorRefFactory: ActorRefFactory): RabbitSystem =
    apply(Option(config), Option(classLoader))(actorRefFactory)

  def apply(config: Option[Config], classLoader: Option[ClassLoader])(implicit actorRefFactory: ActorRefFactory): RabbitSystem = {
    val cl = classLoader.getOrElse(findClassLoader())
    val rabbitConfig = config.getOrElse(ConfigFactory.load(cl))
    new RabbitSystem(rabbitConfig, cl)(actorRefFactory)
  }

  class Settings(classLoader: ClassLoader, cfg: Config) {

    /**
     * The Config backing this RabbitSystem's Settings
     */
    final val config: Config = {
      val config = cfg.withFallback(ConfigFactory.load(classLoader))
      config.checkValid(ConfigFactory.defaultReference(classLoader), "rabbit")
      config
    }

    import config._

    final val host: String = getString("rabbit.host")
    final val port: Int = getInt("rabbit.port")
    final val username: String = getString("rabbit.username")
    final val password: String = getString("rabbit.password")
    final val virtualHost: String = getString("rabbit.virtual-host")
    final val connectionTimeout: Int = getInt("rabbit.connection-timeout")
    final val requestedChannelMax: Int = getInt("rabbit.requested-channel-max")
    final val requestedFrameMax: Int = getInt("rabbit.requested-frame-max")
    final val requestedHeartbeat: Int = getInt("rabbit.requested-heartbeat")

    /**
     * Returns the String representation of the Config that this Settings is backed by
     */
    override def toString: String = config.root.render
  }

  private[rabbit] def findClassLoader(): ClassLoader = {
    Option(Thread.currentThread.getContextClassLoader) getOrElse
      getClass.getClassLoader
  }

}

class RabbitSystem(rabbitConfig: Config, classLoader: ClassLoader)(implicit _actorRefFactory: ActorRefFactory) {

  import RabbitSystem._

  /**
   * The core settings extracted from the supplied configuration.
   */
  final val settings: Settings = new Settings(classLoader, rabbitConfig)

  private val actorRefFactory = _actorRefFactory

  // Connection constructors
  def createConnection(): ActorRef = actorRefFactory.actorOf(ConnectionKeeper.props(settings))
  def createConnection(name: String): ActorRef = actorRefFactory.actorOf(ConnectionKeeper.props(settings), name)

  // Producer constructors
  def createProducer(connectionKeeper: ActorRef): ActorRef =
    createProducer(connectionKeeper, None)
  def createProducer(connectionKeeper: ActorRef, name: String): ActorRef =
    createProducer(connectionKeeper, name = Some(name))
  def createProducer(connectionKeeper: ActorRef, channelConfig: ChannelConfig): ActorRef =
    createProducer(connectionKeeper, Some(channelConfig))
  def createProducer(connectionKeeper: ActorRef, channelConfig: ChannelConfig, name: String): ActorRef =
    createProducer(connectionKeeper, Some(channelConfig), name = Some(name))
  def createProducer(connectionKeeper: ActorRef, channelConfig: Option[ChannelConfig] = None, provision: Seq[RabbitRequest] = Seq.empty[RabbitRequest], name: Option[String] = None, timeout: FiniteDuration = 5000.millis): ActorRef = {
    val futureProducer = (connectionKeeper ? ConnectionKeeper.CreateChild(Producer.props(channelConfig, provision), name))(timeout).mapTo[ActorRef]
    Await.result(futureProducer, timeout)
  }

  // Consumer constructors
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, name: String): ActorRef =
    createConsumer(connectionKeeper, listener, name = Some(name))
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, name: String, autoAck: Boolean): ActorRef =
    createConsumer(connectionKeeper, listener, name = Some(name), autoAck = autoAck)
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, consumeQueueConfig: QueueConfig): ActorRef =
    createConsumer(connectionKeeper, listener, consumeQueueConfig = Some(consumeQueueConfig))
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, consumeQueueConfig: QueueConfig, autoAck: Boolean): ActorRef =
    createConsumer(connectionKeeper, listener, consumeQueueConfig = Some(consumeQueueConfig), autoAck = autoAck)
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, consumeQueueConfig: QueueConfig, name: String): ActorRef =
    createConsumer(connectionKeeper, listener, consumeQueueConfig = Some(consumeQueueConfig), name = Some(name))
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, consumeQueueConfig: QueueConfig, name: String, autoAck: Boolean): ActorRef =
    createConsumer(connectionKeeper, listener, consumeQueueConfig = Some(consumeQueueConfig), name = Some(name), autoAck = autoAck)
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: ChannelConfig): ActorRef =
    createConsumer(connectionKeeper, listener, Some(channelConfig))
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: ChannelConfig, autoAck: Boolean): ActorRef =
    createConsumer(connectionKeeper, listener, Some(channelConfig), autoAck = autoAck)
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: ChannelConfig, name: String): ActorRef =
    createConsumer(connectionKeeper, listener, Some(channelConfig), name = Some(name))
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: ChannelConfig, name: String, autoAck: Boolean): ActorRef =
    createConsumer(connectionKeeper, listener, Some(channelConfig), name = Some(name), autoAck = autoAck)
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: ChannelConfig, consumeQueueConfig: QueueConfig): ActorRef =
    createConsumer(connectionKeeper, listener, Some(channelConfig), Some(consumeQueueConfig))
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: ChannelConfig, consumeQueueConfig: QueueConfig, autoAck: Boolean): ActorRef =
    createConsumer(connectionKeeper, listener, Some(channelConfig), Some(consumeQueueConfig), autoAck = autoAck)
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: ChannelConfig, consumeQueueConfig: QueueConfig, name: String): ActorRef =
    createConsumer(connectionKeeper, listener, Some(channelConfig), Some(consumeQueueConfig), name = Some(name))
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: ChannelConfig, consumeQueueConfig: QueueConfig, name: String, autoAck: Boolean): ActorRef =
    createConsumer(connectionKeeper, listener, Some(channelConfig), Some(consumeQueueConfig), name = Some(name), autoAck = autoAck)
  def createConsumer(connectionKeeper: ActorRef, listener: ActorRef, channelConfig: Option[ChannelConfig] = None, consumeQueueConfig: Option[QueueConfig] = None, provision: Seq[RabbitRequest] = Seq.empty[RabbitRequest], name: Option[String] = None, autoAck: Boolean = false, timeout: FiniteDuration = 5000.millis): ActorRef = {
    val preProvision: Seq[RabbitRequest] = consumeQueueConfig match {
      case Some(cfg) => Seq(ConsumeQueue(cfg))
      case None      => Seq.empty[RabbitRequest]
    }
    val futureConsumer = (connectionKeeper ? ConnectionKeeper.CreateChild(Consumer.props(listener, autoAck, channelConfig, preProvision ++ provision), name))(timeout).mapTo[ActorRef]
    Await.result(futureConsumer, timeout)
  }

  // RPCServer constructors
  def createRPCServer(connectionKeeper: ActorRef, processor: RabbitRPCProcessor, name: String): ActorRef =
    createRPCServer(connectionKeeper, processor, name = Some(name))
  def createRPCServer(connectionKeeper: ActorRef, processor: RabbitRPCProcessor, consumeQueueConfig: QueueConfig): ActorRef =
    createRPCServer(connectionKeeper, processor, consumeQueueConfig = Some(consumeQueueConfig))
  def createRPCServer(connectionKeeper: ActorRef, processor: RabbitRPCProcessor, consumeQueueConfig: QueueConfig, name: String): ActorRef =
    createRPCServer(connectionKeeper, processor, consumeQueueConfig = Some(consumeQueueConfig), name = Some(name))
  def createRPCServer(connectionKeeper: ActorRef, processor: RabbitRPCProcessor, channelConfig: ChannelConfig): ActorRef =
    createRPCServer(connectionKeeper, processor, Some(channelConfig))
  def createRPCServer(connectionKeeper: ActorRef, processor: RabbitRPCProcessor, channelConfig: ChannelConfig, name: String): ActorRef =
    createRPCServer(connectionKeeper, processor, Some(channelConfig), name = Some(name))
  def createRPCServer(connectionKeeper: ActorRef, processor: RabbitRPCProcessor, channelConfig: ChannelConfig, consumeQueueConfig: QueueConfig): ActorRef =
    createRPCServer(connectionKeeper, processor, Some(channelConfig), Some(consumeQueueConfig))
  def createRPCServer(connectionKeeper: ActorRef, processor: RabbitRPCProcessor, channelConfig: ChannelConfig, consumeQueueConfig: QueueConfig, name: String): ActorRef =
    createRPCServer(connectionKeeper, processor, Some(channelConfig), Some(consumeQueueConfig), name = Some(name))
  def createRPCServer(connectionKeeper: ActorRef, processor: RabbitRPCProcessor, channelConfig: Option[ChannelConfig] = None, consumeQueueConfig: Option[QueueConfig] = None, provision: Seq[RabbitRequest] = Seq.empty[RabbitRequest], name: Option[String] = None, timeout: FiniteDuration = 5000.millis): ActorRef = {
    val preProvision: Seq[RabbitRequest] = consumeQueueConfig match {
      case Some(cfg) => Seq(ConsumeQueue(cfg))
      case None      => Seq.empty[RabbitRequest]
    }
    val futureRPCServer = (connectionKeeper ? ConnectionKeeper.CreateChild(RPCServer.props(processor, channelConfig, preProvision ++ provision), name))(timeout).mapTo[ActorRef]
    Await.result(futureRPCServer, timeout)
  }

  // RPCClient constructors
  def createRPCClient(connectionKeeper: ActorRef, name: String): ActorRef =
    createRPCClient(connectionKeeper, name = Some(name))
  def createRPCClient(connectionKeeper: ActorRef, channelConfig: ChannelConfig): ActorRef =
    createRPCClient(connectionKeeper, Some(channelConfig))
  def createRPCClient(connectionKeeper: ActorRef, channelConfig: ChannelConfig, name: String): ActorRef =
    createRPCClient(connectionKeeper, Some(channelConfig), name = Some(name))
  def createRPCClient(connectionKeeper: ActorRef, channelConfig: Option[ChannelConfig] = None, provision: Seq[RabbitRequest] = Seq.empty[RabbitRequest], name: Option[String] = None, timeout: FiniteDuration = 5000.millis): ActorRef = {
    val futureRPCClient = (connectionKeeper ? ConnectionKeeper.CreateChild(RPCClient.props(channelConfig, provision), name))(timeout).mapTo[ActorRef]
    Await.result(futureRPCClient, timeout)
  }

  def onConnected(actor: ActorRef, onConnected: () => Unit): Unit = {
    val callbackActor = actorRefFactory.actorOf(Props(new Actor{
      override def receive: Actor.Receive = {
        case ConnectionKeeper.Connected | ChannelKeeper.Connected =>
          onConnected()
          context.stop(self)
      }
    }))
    actor ! Observable.RegisterObserver(callbackActor)
  }

  def waitForConnectionOf(actors: ActorRef*): Unit = {
    val countDownLatch = new CountDownLatch(actors.size)
    actors.foreach(a => onConnected(a, () => countDownLatch.countDown()))
    countDownLatch.await()
  }

  def waitFor(constructor: => ActorRef): ActorRef = {
    val actor = constructor
    waitForConnectionOf(actor)
    actor
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy