summaryrefslogtreecommitdiff
path: root/odcsim-core/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'odcsim-core/src/main')
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt26
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt5
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt13
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt17
-rw-r--r--odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt7
5 files changed, 53 insertions, 15 deletions
diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt
index 499e7df0..f8128490 100644
--- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt
+++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt
@@ -38,6 +38,11 @@ interface ActorContext<T : Any> {
val self: ActorRef<T>
/**
+ * A view of the children of this actor.
+ */
+ val children: List<ActorRef<*>>
+
+ /**
* The point of time within the simulation.
*/
val time: Instant
@@ -53,6 +58,14 @@ interface ActorContext<T : Any> {
val log: Logger
/**
+ * Obtain the child of this actor with the specified name.
+ *
+ * @param name The name of the child actor to obtain.
+ * @return The reference to the child actor or `null` if it does not exist.
+ */
+ fun getChild(name: String): ActorRef<*>?
+
+ /**
* Send the specified message to the actor referenced by this [ActorRef].
*
* Please note that callees must guarantee that messages are sent strictly in increasing time.
@@ -69,6 +82,9 @@ interface ActorContext<T : Any> {
/**
* Spawn a child actor from the given [Behavior] and with the specified name.
*
+ * The name may not be empty or start with "$". Moreover, the name of an actor must be unique and this method
+ * will throw an [IllegalArgumentException] in case a child actor of the given name already exists.
+ *
* @param behavior The behavior of the child actor to spawn.
* @param name The name of the child actor to spawn.
* @return A reference to the child that has/will be spawned.
@@ -84,12 +100,16 @@ interface ActorContext<T : Any> {
fun <U : Any> spawnAnonymous(behavior: Behavior<U>): ActorRef<U>
/**
- * Request the specified child actor to be stopped in asynchronous fashion.
+ * Force the specified child actor to terminate after it finishes processing its current message.
+ * Nothing will happen if the child is already stopped.
+ *
+ * Only direct children of an actor may be stopped through the actor context. Trying to stop other actors via this
+ * method will result in an [IllegalArgumentException]. Instead, stopping other actors has to be expressed as
+ * an explicit stop message that the actor accept.
*
* @param child The reference to the child actor to stop.
- * @return `true` if the ref points to a child actor, otherwise `false`.
*/
- fun stop(child: ActorRef<*>): Boolean
+ fun stop(child: ActorRef<*>)
/**
* Watch the specified [ActorRef] for termination of the referenced actor. On termination of the watched actor,
diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt
index f51a4fed..a6c716a2 100644
--- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt
+++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt
@@ -51,6 +51,11 @@ sealed class ActorPath : Comparable<ActorPath>, Serializable {
fun child(name: String): ActorPath = Child(this, name)
/**
+ * Create a new child actor path.
+ */
+ operator fun div(name: String): ActorPath = child(name)
+
+ /**
* Recursively create a descendant’s path by appending all child names.
*/
fun descendant(children: Iterable<String>): ActorPath = children.fold(this) { parent, name ->
diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt
index bae1fb74..d65beebd 100644
--- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt
+++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt
@@ -59,11 +59,18 @@ interface ActorSystem<in T : Any> : ActorRef<T> {
fun send(msg: T, after: Duration = 0.1)
/**
- * Terminates this actor system.
+ * Terminates this actor system in an asynchronous fashion.
*
* This will stop the root actor and in turn will recursively stop all its child actors.
- *
- * This is an asynchronous operation.
*/
fun terminate()
+
+ /**
+ * Create an actor in the "/system" namespace. This actor will be shut down during `system.terminate()` only after
+ * all user actors have terminated.
+ *
+ * @param behavior The behavior of the system actor to spawn.
+ * @param name The name of the system actor to spawn.
+ */
+ suspend fun <U : Any> spawnSystem(behavior: Behavior<U>, name: String): ActorRef<U>
}
diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt
index 2ad042e3..9b707348 100644
--- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt
+++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt
@@ -37,10 +37,19 @@ object PreStart : Signal
/**
* Lifecycle signal that is fired after this actor and all its child actors (transitively) have terminated.
+ * The [Terminated] signal is only sent to registered watchers after this signal has been processed.
*/
object PostStop : Signal
/**
+ * A lifecycle signal to indicate that an actor that was watched has terminated.
+ *
+ * @property ref The reference to the actor that has terminated.
+ * @property failure The failure that caused the termination, or `null` on graceful termination.
+ */
+data class Terminated(val ref: ActorRef<*>, val failure: Throwable? = null) : Signal
+
+/**
* A [Signal] to indicate an actor has timed out.
*
* This class contains a [target] property in order to allow nested behavior to function properly when multiple layers
@@ -49,11 +58,3 @@ object PostStop : Signal
* @property target The target object that has timed out.
*/
data class Timeout(val target: Any) : Signal
-
-/**
- * A lifecycle signal to indicate that an actor that was watched has terminated.
- *
- * @property ref The reference to the actor that has terminated.
- * @property failure The failure that caused the termination, or `null` on graceful termination.
- */
-data class Terminated(val ref: ActorRef<*>, val failure: Throwable? = null) : Signal
diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt
index 13e722fc..f9e8de00 100644
--- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt
+++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt
@@ -95,19 +95,24 @@ internal class SuspendingBehaviorImpl<T : Any>(
override val time: Instant get() = actorContext.time
+ override val children: List<ActorRef<*>>
+ get() = actorContext.children
+
override val system: ActorSystem<*>
get() = actorContext.system
override val log: Logger
get() = actorContext.log
+ override fun getChild(name: String): ActorRef<*>? = actorContext.getChild(name)
+
override fun <U : Any> send(ref: ActorRef<U>, msg: U, after: Duration) = actorContext.send(ref, msg, after)
override fun <U : Any> spawn(behavior: Behavior<U>, name: String) = actorContext.spawn(behavior, name)
override fun <U : Any> spawnAnonymous(behavior: Behavior<U>) = actorContext.spawnAnonymous(behavior)
- override fun stop(child: ActorRef<*>): Boolean = actorContext.stop(child)
+ override fun stop(child: ActorRef<*>) = actorContext.stop(child)
override fun watch(target: ActorRef<*>) = actorContext.watch(target)