alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Akka/Scala example source code file (ChildrenContainer.scala)

This example Akka source code file (ChildrenContainer.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Akka and Scala source code examples by using tags.

All credit for the original source code belongs to akka.io; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Akka tags/keywords

actor, actorref, akka, boolean, childrencontainer, childrestartstats, childstats, collection, dispatch, emptyimmutableseq, normalchildrencontainer, option, string, suspendreason

The ChildrenContainer.scala Akka example source code

/**
 * Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
 */

package akka.actor.dungeon

import scala.collection.immutable

import akka.actor.{ InvalidActorNameException, ChildStats, ChildRestartStats, ChildNameReserved, ActorRef }
import akka.dispatch.sysmsg.{ EarliestFirstSystemMessageList, SystemMessageList, LatestFirstSystemMessageList, SystemMessage }
import akka.util.Collections.{ EmptyImmutableSeq, PartialImmutableValuesIterable }

/**
 * INTERNAL API
 */
private[akka] trait ChildrenContainer {

  def add(name: String, stats: ChildRestartStats): ChildrenContainer
  def remove(child: ActorRef): ChildrenContainer

  def getByName(name: String): Option[ChildStats]
  def getByRef(actor: ActorRef): Option[ChildRestartStats]

  def children: immutable.Iterable[ActorRef]
  def stats: immutable.Iterable[ChildRestartStats]

  def shallDie(actor: ActorRef): ChildrenContainer

  // reserve that name or throw an exception
  def reserve(name: String): ChildrenContainer
  // cancel a reservation
  def unreserve(name: String): ChildrenContainer

  def isTerminating: Boolean = false
  def isNormal: Boolean = true
}

/**
 * INTERNAL API
 *
 * This object holds the classes performing the logic of managing the children
 * of an actor, hence they are intimately tied to ActorCell.
 */
private[akka] object ChildrenContainer {

  sealed trait SuspendReason
  case object UserRequest extends SuspendReason
  // careful with those system messages, all handling to be taking place in ActorCell.scala!
  final case class Recreation(cause: Throwable) extends SuspendReason with WaitingForChildren
  final case class Creation() extends SuspendReason with WaitingForChildren
  case object Termination extends SuspendReason

  class ChildRestartsIterable(stats: immutable.MapLike[_, ChildStats, _]) extends PartialImmutableValuesIterable[ChildStats, ChildRestartStats] {
    override final def apply(c: ChildStats) = c.asInstanceOf[ChildRestartStats]
    override final def isDefinedAt(c: ChildStats) = c.isInstanceOf[ChildRestartStats]
    override final def valuesIterator = stats.valuesIterator
  }

  class ChildrenIterable(stats: immutable.MapLike[_, ChildStats, _]) extends PartialImmutableValuesIterable[ChildStats, ActorRef] {
    override final def apply(c: ChildStats) = c.asInstanceOf[ChildRestartStats].child
    override final def isDefinedAt(c: ChildStats) = c.isInstanceOf[ChildRestartStats]
    override final def valuesIterator = stats.valuesIterator
  }

  trait WaitingForChildren

  trait EmptyChildrenContainer extends ChildrenContainer {
    val emptyStats = immutable.TreeMap.empty[String, ChildStats]
    override def add(name: String, stats: ChildRestartStats): ChildrenContainer = new NormalChildrenContainer(emptyStats.updated(name, stats))
    override def remove(child: ActorRef): ChildrenContainer = this
    override def getByName(name: String): Option[ChildRestartStats] = None
    override def getByRef(actor: ActorRef): Option[ChildRestartStats] = None
    override def children: immutable.Iterable[ActorRef] = EmptyImmutableSeq
    override def stats: immutable.Iterable[ChildRestartStats] = EmptyImmutableSeq
    override def shallDie(actor: ActorRef): ChildrenContainer = this
    override def reserve(name: String): ChildrenContainer = new NormalChildrenContainer(emptyStats.updated(name, ChildNameReserved))
    override def unreserve(name: String): ChildrenContainer = this
  }

  /**
   * This is the empty container, shared among all leaf actors.
   */
  object EmptyChildrenContainer extends EmptyChildrenContainer {
    override def toString = "no children"
  }

  /**
   * This is the empty container which is installed after the last child has
   * terminated while stopping; it is necessary to distinguish from the normal
   * empty state while calling handleChildTerminated() for the last time.
   */
  object TerminatedChildrenContainer extends EmptyChildrenContainer {
    override def add(name: String, stats: ChildRestartStats): ChildrenContainer = this
    override def reserve(name: String): ChildrenContainer =
      throw new IllegalStateException("cannot reserve actor name '" + name + "': already terminated")
    override def isTerminating: Boolean = true
    override def isNormal: Boolean = false
    override def toString = "terminated"
  }

  /**
   * Normal children container: we do have at least one child, but none of our
   * children are currently terminating (which is the time period between
   * calling context.stop(child) and processing the ChildTerminated() system
   * message).
   */
  class NormalChildrenContainer(val c: immutable.TreeMap[String, ChildStats]) extends ChildrenContainer {

    override def add(name: String, stats: ChildRestartStats): ChildrenContainer = new NormalChildrenContainer(c.updated(name, stats))

    override def remove(child: ActorRef): ChildrenContainer = NormalChildrenContainer(c - child.path.name)

    override def getByName(name: String): Option[ChildStats] = c.get(name)

    override def getByRef(actor: ActorRef): Option[ChildRestartStats] = c.get(actor.path.name) match {
      case c @ Some(crs: ChildRestartStats) if (crs.child == actor) ⇒ c.asInstanceOf[Option[ChildRestartStats]]
      case _ ⇒ None
    }

    override def children: immutable.Iterable[ActorRef] =
      if (c.isEmpty) EmptyImmutableSeq else new ChildrenIterable(c)

    override def stats: immutable.Iterable[ChildRestartStats] =
      if (c.isEmpty) EmptyImmutableSeq else new ChildRestartsIterable(c)

    override def shallDie(actor: ActorRef): ChildrenContainer = TerminatingChildrenContainer(c, Set(actor), UserRequest)

    override def reserve(name: String): ChildrenContainer =
      if (c contains name)
        throw new InvalidActorNameException(s"actor name [$name] is not unique!")
      else new NormalChildrenContainer(c.updated(name, ChildNameReserved))

    override def unreserve(name: String): ChildrenContainer = c.get(name) match {
      case Some(ChildNameReserved) ⇒ NormalChildrenContainer(c - name)
      case _                       ⇒ this
    }

    override def toString =
      if (c.size > 20) c.size + " children"
      else c.mkString("children:\n    ", "\n    ", "")
  }

  object NormalChildrenContainer {
    def apply(c: immutable.TreeMap[String, ChildStats]): ChildrenContainer =
      if (c.isEmpty) EmptyChildrenContainer
      else new NormalChildrenContainer(c)
  }

  /**
   * Waiting state: there are outstanding termination requests (i.e. context.stop(child)
   * was called but the corresponding ChildTerminated() system message has not yet been
   * processed). There could be no specific reason (UserRequested), we could be Restarting
   * or Terminating.
   *
   * Removing the last child which was supposed to be terminating will return a different
   * type of container, depending on whether or not children are left and whether or not
   * the reason was “Terminating”.
   */
  final case class TerminatingChildrenContainer(c: immutable.TreeMap[String, ChildStats], toDie: Set[ActorRef], reason: SuspendReason)
    extends ChildrenContainer {

    override def add(name: String, stats: ChildRestartStats): ChildrenContainer = copy(c.updated(name, stats))

    override def remove(child: ActorRef): ChildrenContainer = {
      val t = toDie - child
      if (t.isEmpty) reason match {
        case Termination ⇒ TerminatedChildrenContainer
        case _           ⇒ NormalChildrenContainer(c - child.path.name)
      }
      else copy(c - child.path.name, t)
    }

    override def getByName(name: String): Option[ChildStats] = c.get(name)

    override def getByRef(actor: ActorRef): Option[ChildRestartStats] = c.get(actor.path.name) match {
      case c @ Some(crs: ChildRestartStats) if (crs.child == actor) ⇒ c.asInstanceOf[Option[ChildRestartStats]]
      case _ ⇒ None
    }

    override def children: immutable.Iterable[ActorRef] =
      if (c.isEmpty) EmptyImmutableSeq else new ChildrenIterable(c)

    override def stats: immutable.Iterable[ChildRestartStats] =
      if (c.isEmpty) EmptyImmutableSeq else new ChildRestartsIterable(c)

    override def shallDie(actor: ActorRef): ChildrenContainer = copy(toDie = toDie + actor)

    override def reserve(name: String): ChildrenContainer = reason match {
      case Termination ⇒ throw new IllegalStateException("cannot reserve actor name '" + name + "': terminating")
      case _ ⇒
        if (c contains name)
          throw new InvalidActorNameException(s"actor name [$name] is not unique!")
        else copy(c = c.updated(name, ChildNameReserved))
    }

    override def unreserve(name: String): ChildrenContainer = c.get(name) match {
      case Some(ChildNameReserved) ⇒ copy(c = c - name)
      case _                       ⇒ this
    }

    override def isTerminating: Boolean = reason == Termination
    override def isNormal: Boolean = reason == UserRequest

    override def toString =
      if (c.size > 20) c.size + " children"
      else c.mkString("children (" + toDie.size + " terminating):\n    ", "\n    ", "\n") + toDie
  }

}

Other Akka source code examples

Here is a short list of links related to this Akka ChildrenContainer.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.