From 1f77d1011577c54e98ad0cbbd898817f98000881 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 8 May 2019 11:42:05 +0200 Subject: feat: Add support for spawning anonymous children This change adds support for spawning anonymous children in an ActorContext. This means a name does not have to be specified when spawning an actor. --- .../src/main/kotlin/com/atlarge/odcsim/ActorContext.kt | 8 ++++++++ .../main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt | 2 +- .../main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt | 2 ++ .../src/test/kotlin/com/atlarge/odcsim/CoroutinesTest.kt | 2 +- .../com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt | 12 +++++++++++- .../com/atlarge/odcsim/engine/tests/ActorSystemContract.kt | 1 - .../com/atlarge/odcsim/testkit/internal/ActorContextStub.kt | 5 +++++ 7 files changed, 28 insertions(+), 4 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 8ea4a09d..499e7df0 100644 --- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt @@ -75,6 +75,14 @@ interface ActorContext { */ fun spawn(behavior: Behavior, name: String): ActorRef + /** + * Spawn an anonymous child actor from the given [Behavior]. + * + * @param behavior The behavior of the child actor to spawn. + * @return A reference to the child that has/will be spawned. + */ + fun spawnAnonymous(behavior: Behavior): ActorRef + /** * Request the specified child actor to be stopped in asynchronous fashion. * diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt index b963cdb6..eb26add1 100644 --- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt @@ -32,8 +32,8 @@ import com.atlarge.odcsim.internal.SuspendingActorContextImpl import com.atlarge.odcsim.internal.SuspendingBehaviorImpl import kotlin.coroutines.Continuation import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn +import kotlin.coroutines.suspendCoroutine /** * A [Behavior] that allows method calls to suspend execution via Kotlin coroutines. 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 a9e20d0e..13e722fc 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 @@ -105,6 +105,8 @@ internal class SuspendingBehaviorImpl( override fun spawn(behavior: Behavior, name: String) = actorContext.spawn(behavior, name) + override fun spawnAnonymous(behavior: Behavior) = actorContext.spawnAnonymous(behavior) + override fun stop(child: ActorRef<*>): Boolean = actorContext.stop(child) override fun watch(target: ActorRef<*>) = actorContext.watch(target) diff --git a/odcsim-core/src/test/kotlin/com/atlarge/odcsim/CoroutinesTest.kt b/odcsim-core/src/test/kotlin/com/atlarge/odcsim/CoroutinesTest.kt index d6bf6a74..98486149 100644 --- a/odcsim-core/src/test/kotlin/com/atlarge/odcsim/CoroutinesTest.kt +++ b/odcsim-core/src/test/kotlin/com/atlarge/odcsim/CoroutinesTest.kt @@ -24,8 +24,8 @@ package com.atlarge.odcsim -import com.atlarge.odcsim.coroutines.suspending import com.atlarge.odcsim.coroutines.SuspendingBehavior +import com.atlarge.odcsim.coroutines.suspending import com.atlarge.odcsim.internal.BehaviorInterpreter import com.atlarge.odcsim.internal.EmptyBehavior import com.nhaarman.mockitokotlin2.mock diff --git a/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt b/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt index 8930fb96..37b5395f 100644 --- a/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt +++ b/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt @@ -38,10 +38,10 @@ import com.atlarge.odcsim.Signal import com.atlarge.odcsim.Terminated import com.atlarge.odcsim.internal.BehaviorInterpreter import com.atlarge.odcsim.internal.logging.LoggerImpl -import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl import org.slf4j.Logger import java.util.Collections import java.util.PriorityQueue +import java.util.UUID import java.util.WeakHashMap import kotlin.math.max @@ -155,6 +155,16 @@ class OmegaActorSystem(root: Behavior, override val name: String) override fun send(ref: ActorRef, msg: U, after: Duration) = schedule(ref, msg, after) override fun spawn(behavior: Behavior, name: String): ActorRef { + require(!name.startsWith("$")) { "Name may not start with $-sign" } + return internalSpawn(behavior, name) + } + + override fun spawnAnonymous(behavior: Behavior): ActorRef { + val name = "$" + UUID.randomUUID() + return internalSpawn(behavior, name) + } + + private fun internalSpawn(behavior: Behavior, name: String): ActorRef { val ref = ActorRefImpl(this@OmegaActorSystem, self.path.child(name)) if (ref.path !in registry) { val actor = Actor(ref, behavior) diff --git a/odcsim-engine-tests/src/main/kotlin/com/atlarge/odcsim/engine/tests/ActorSystemContract.kt b/odcsim-engine-tests/src/main/kotlin/com/atlarge/odcsim/engine/tests/ActorSystemContract.kt index 867e7c11..e7639db8 100644 --- a/odcsim-engine-tests/src/main/kotlin/com/atlarge/odcsim/engine/tests/ActorSystemContract.kt +++ b/odcsim-engine-tests/src/main/kotlin/com/atlarge/odcsim/engine/tests/ActorSystemContract.kt @@ -29,7 +29,6 @@ import com.atlarge.odcsim.ActorRef import com.atlarge.odcsim.ActorSystemFactory import com.atlarge.odcsim.Behavior import com.atlarge.odcsim.Terminated -import com.atlarge.odcsim.coroutines.dsl.timeout import com.atlarge.odcsim.coroutines.suspending import com.atlarge.odcsim.empty import com.atlarge.odcsim.ignore diff --git a/odcsim-testkit/src/main/kotlin/com/atlarge/odcsim/testkit/internal/ActorContextStub.kt b/odcsim-testkit/src/main/kotlin/com/atlarge/odcsim/testkit/internal/ActorContextStub.kt index 047e4c70..7035b908 100644 --- a/odcsim-testkit/src/main/kotlin/com/atlarge/odcsim/testkit/internal/ActorContextStub.kt +++ b/odcsim-testkit/src/main/kotlin/com/atlarge/odcsim/testkit/internal/ActorContextStub.kt @@ -32,6 +32,7 @@ import com.atlarge.odcsim.Duration import com.atlarge.odcsim.Instant import com.atlarge.odcsim.internal.logging.LoggerImpl import org.slf4j.Logger +import java.util.UUID /** * A stubbed [ActorContext] implementation for synchronous behavior testing. @@ -72,6 +73,10 @@ internal class ActorContextStub(private val owner: BehaviorTestKitImpl< return btk.ref } + override fun spawnAnonymous(behavior: Behavior): ActorRef { + return spawn(behavior, "$" + UUID.randomUUID()) + } + override fun stop(child: ActorRef<*>): Boolean { if (child.path.parent != self.path) { // This is not a child of this actor -- cgit v1.2.3