pekko/akka-camel/src/main/scala/akka/camel/internal/ActivationTracker.scala
RayRoestenburg d0a50f66e7 Tickets #1924 #1925 #2383 #2387 #1927 #1926
Changed unlimited blocking to block up untill the replyTimeout, and added a test for it, where manual Ack is never received ticket #1926

removed unnecesary methods
2012-09-25 17:57:07 -05:00

117 lines
No EOL
4.1 KiB
Scala

/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.camel.internal
import akka.actor._
import collection.mutable.WeakHashMap
import akka.camel._
import internal.ActivationProtocol._
/**
* For internal use only. An actor that tracks activation and de-activation of endpoints.
*/
private[akka] final class ActivationTracker extends Actor with ActorLogging {
val activations = new WeakHashMap[ActorRef, ActivationStateMachine]
/**
* A state machine that keeps track of the endpoint activation status of an actor.
*/
class ActivationStateMachine {
type State = PartialFunction[ActivationMessage, Unit]
var receive: State = notActivated()
/**
* Not activated state
* @return a partial function that handles messages in the 'not activated' state
*/
def notActivated(): State = {
var awaitingActivation = List[ActorRef]()
var awaitingDeActivation = List[ActorRef]()
{
case AwaitActivation(ref) awaitingActivation ::= sender
case AwaitDeActivation(ref) awaitingDeActivation ::= sender
case msg @ EndpointActivated(ref)
awaitingActivation.foreach(_ ! msg)
receive = activated(awaitingDeActivation)
case EndpointFailedToActivate(ref, cause)
awaitingActivation.foreach(_ ! EndpointFailedToActivate(ref, cause))
receive = failedToActivate(cause)
}
}
/**
* Activated state.
* @param currentAwaitingDeActivation the current <code>ActorRef</code>s awaiting de-activation
* @return a partial function that handles messages in the 'activated' state
*/
def activated(currentAwaitingDeActivation: List[ActorRef]): State = {
var awaitingDeActivation = currentAwaitingDeActivation
{
case AwaitActivation(ref) sender ! EndpointActivated(ref)
case AwaitDeActivation(ref) awaitingDeActivation ::= sender
case msg @ EndpointDeActivated(ref)
awaitingDeActivation foreach (_ ! msg)
receive = deactivated
case msg @ EndpointFailedToDeActivate(ref, cause)
awaitingDeActivation foreach (_ ! msg)
receive = failedToDeActivate(cause)
}
}
/**
* De-activated state
* @return a partial function that handles messages in the 'de-activated' state
*/
def deactivated: State = {
case AwaitActivation(ref) sender ! EndpointActivated(ref)
case AwaitDeActivation(ref) sender ! EndpointDeActivated(ref)
}
/**
* Failed to activate state
* @param cause the cause for the failure
* @return a partial function that handles messages in 'failed to activate' state
*/
def failedToActivate(cause: Throwable): State = {
case AwaitActivation(ref) sender ! EndpointFailedToActivate(ref, cause)
case AwaitDeActivation(ref) sender ! EndpointFailedToActivate(ref, cause)
}
/**
* Failed to de-activate state
* @param cause the cause for the failure
* @return a partial function that handles messages in 'failed to de-activate' state
*/
def failedToDeActivate(cause: Throwable): State = {
case AwaitActivation(ref) sender ! EndpointActivated(ref)
case AwaitDeActivation(ref) sender ! EndpointFailedToDeActivate(ref, cause)
}
}
override def receive = {
case msg @ ActivationMessage(ref)
(activations.getOrElseUpdate(ref, new ActivationStateMachine).receive orElse logStateWarning(ref))(msg)
}
private[this] def logStateWarning(actorRef: ActorRef): Receive =
{ case msg log.warning("Message [{}] not expected in current state of actor [{}]", msg, actorRef) }
}
/**
* For internal use only. A request message to the ActivationTracker for the status of activation.
* @param ref the actorRef
*/
private[camel] case class AwaitActivation(ref: ActorRef) extends ActivationMessage(ref)
/**
* For internal use only. A request message to the ActivationTracker for the status of de-activation.
* For internal use only.
* @param ref the actorRef
*/
private[camel] case class AwaitDeActivation(ref: ActorRef) extends ActivationMessage(ref)