summaryrefslogtreecommitdiff
path: root/odcsim/odcsim-api/src/main/kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'odcsim/odcsim-api/src/main/kotlin')
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt175
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt142
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt76
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behavior.kt169
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behaviors.kt223
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Channel.kt70
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Envelope.kt57
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Port.kt64
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ProcessContext.kt82
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ProcessRef.kt (renamed from odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/dsl/Timeout.kt)31
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Signals.kt60
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngine.kt (renamed from odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorRef.kt)28
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngineProvider.kt (renamed from odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorSystemFactory.kt)10
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/StashBuffer.kt88
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Time.kt75
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/TimerScheduler.kt92
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt116
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/dsl/Receive.kt66
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/ActorContext.kt43
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/Behavior.kt48
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/BehaviorInterpreter.kt201
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt182
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/StashBufferImpl.kt74
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/TimerSchedulerImpl.kt122
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LocationAwareLoggerImpl.kt567
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LocationIgnorantLoggerImpl.kt440
-rw-r--r--odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LoggerImpl.kt77
27 files changed, 254 insertions, 3124 deletions
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt
deleted file mode 100644
index dc6ca7ec..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim
-
-import org.slf4j.Logger
-
-/**
- * Represents the context in which the execution of an actor's behavior takes place.
- *
- * @param T The shape of the messages the actor accepts.
- */
-interface ActorContext<T : Any> {
- /**
- * The identity of the actor, bound to the lifecycle of this actor instance.
- */
- 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
-
- /**
- * The [ActorSystem] the actor is part of.
- */
- val system: ActorSystem<*>
-
- /**
- * An actor specific logger instance.
- */
- 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.
- * If so, this method guarantees that:
- * - A message will never be received earlier than specified
- * - A message might arrive later than specified if the two actors are not synchronized.
- *
- * @param ref The actor to send the message to.
- * @param msg The message to send to the referenced actor.
- * @param after The delay after which the message should be received by the actor.
- */
- fun <U : Any> send(ref: ActorRef<U>, msg: U, after: Duration = 0.0)
-
- /**
- * 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.
- */
- fun <U : Any> spawn(behavior: Behavior<U>, name: String): ActorRef<U>
-
- /**
- * 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 <U : Any> spawnAnonymous(behavior: Behavior<U>): ActorRef<U>
-
- /**
- * 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.
- */
- fun stop(child: ActorRef<*>)
-
- /**
- * Watch the specified [ActorRef] for termination of the referenced actor. On termination of the watched actor,
- * a [Terminated] signal is sent to this actor.
- *
- * @param target The target actor to watch.
- */
- fun watch(target: ActorRef<*>)
-
- /**
- * Revoke the registration established by [watch].
- *
- * In case there exists no registration for the specified [target], no action will be performed.
- *
- * @param target The target actor to unwatch.
- */
- fun unwatch(target: ActorRef<*>)
-
- /**
- * Synchronize the local virtual time of this target with the other referenced actor's local virtual time.
- *
- * By default, actors are not guaranteed to be synchronized, meaning that for some implementations, virtual time may
- * drift between different actors. Synchronization between two actors ensures that virtual time remains consistent
- * between at least the two actors.
- *
- * Be aware that this method may cause a jump in virtual time in order to get consistent with [target].
- * Furthermore, please note that synchronization might incur performance degradation and should only be used
- * when necessary.
- *
- * @param target The reference to the target actor to synchronize with.
- */
- fun sync(target: ActorRef<*>)
-
- /**
- * Desynchronize virtual time between two actors if possible.
- *
- * Please note that this method only provides a hint to the [ActorSystem] that it may drop synchronization between
- * the actors, but [ActorSystem] is not compelled to actually do so (i.e. in the case where synchronization is
- * always guaranteed).
- *
- * Furthermore, if [target] is already desychronized, the method should return without error. [ActorContext.isSync]
- * may be used to determine if an actor is synchronized.
- *
- * @param target The reference to the target actor to desynchronize with.
- */
- fun unsync(target: ActorRef<*>)
-
- /**
- * Determine whether this actor and [target] are synchronized in virtual time.
- *
- * @param target The target to check for synchronization.
- * @return `true` if [target] is synchronized with this actor, `false` otherwise.
- */
- fun isSync(target: ActorRef<*>): Boolean
-}
-
-/**
- * Unsafe helper method for widening the type accepted by this [ActorContext].
- */
-fun <U : Any, T : U> ActorContext<T>.unsafeCast(): ActorContext<U> {
- @Suppress("UNCHECKED_CAST")
- return this as ActorContext<U>
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt
deleted file mode 100644
index a6c716a2..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim
-
-import java.io.Serializable
-
-/**
- * An actor path represents the unique path to a specific actor instance within an [ActorSystem].
- */
-sealed class ActorPath : Comparable<ActorPath>, Serializable {
- /**
- * The name of the actor that this path refers to.
- */
- abstract val name: String
-
- /**
- * The path for the parent actor.
- */
- abstract val parent: ActorPath
-
- /**
- * Walk up the tree to obtain and return the [ActorPath.Root].
- */
- abstract val root: Root
-
- /**
- * Create a new child actor path.
- */
- 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 ->
- if (name.isNotBlank()) child(name) else parent
- }
-
- /**
- * Root of the hierarchy of [ActorPath]s. There is exactly root per [ActorSystem].
- */
- data class Root(override val name: String = "/") : ActorPath() {
- init {
- require(name.length == 1 || name.indexOf('/', 1) == -1) {
- "/ may only exist at the beginning of the root actors name"
- }
- require(name.indexOf('#') == -1) { "# may not exist in a path component" }
- }
-
- override val parent: ActorPath = this
-
- override val root: Root = this
-
- /**
- * Compare the [specified][other] path with this root node for order. If both paths are roots, compare their
- * name, otherwise the root is ordered higher.
- *
- * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater
- * than the specified path.
- */
- override fun compareTo(other: ActorPath): Int = if (other is Root) name.compareTo(other.name) else 1
-
- /**
- * Create a string representation of this root node which prints its own [name].
- *
- * @return A string representation of this node.
- */
- override fun toString(): String = name
- }
-
- /**
- * A child in the hierarchy of [ActorPath]s.
- */
- data class Child(override val parent: ActorPath, override val name: String) : ActorPath() {
- init {
- require(name.indexOf('/') == -1) { "/ may not exist in a path component" }
- require(name.indexOf('#') == -1) { "# may not exist in a path component" }
- }
-
- override val root: Root by lazy {
- when (parent) {
- is Root -> parent
- else -> parent.root
- }
- }
-
- /**
- * Compare the [specified][other] path with this child node for order.
- *
- * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater
- * than the specified path.
- */
- override fun compareTo(other: ActorPath): Int {
- tailrec fun rec(left: ActorPath, right: ActorPath): Int = when {
- left == right -> 0
- left is Root -> left.compareTo(right)
- right is Root -> -(right.compareTo(left))
- else -> {
- val x = left.name.compareTo(right.name)
- if (x == 0)
- rec(left.parent, right.parent)
- else
- x
- }
- }
- return rec(this, other)
- }
-
- /**
- * Create a string representation of this child node which prints the name of [parent] and its own [name].
- *
- * @return A string representation of this node.
- */
- override fun toString(): String = "$parent/$name"
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt
deleted file mode 100644
index d65beebd..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim
-
-/**
- * An actor system is a hierarchical grouping of actors that represents a discrete event simulation.
- *
- * An implementation of this interface should be provided by an engine. See for example *odcsim-engine-omega*,
- * which is the reference implementation of the *odcsim* API.
- *
- * @param T The shape of the messages the root actor in the system can receive.
- */
-interface ActorSystem<in T : Any> : ActorRef<T> {
- /**
- * The current point in simulation time.
- */
- val time: Instant
-
- /**
- * The name of this engine instance, used to distinguish between multiple engines running within the same JVM.
- */
- val name: String
-
- /**
- * Run the actors until the specified point in simulation time.
- *
- * @param until The point until which the simulation should run.
- */
- fun run(until: Duration = Duration.POSITIVE_INFINITY)
-
- /**
- * Send the specified message to the root actor of this [ActorSystem].
- *
- * @param msg The message to send to the referenced actor.
- * @param after The delay after which the message should be received by the actor.
- */
- fun send(msg: T, after: Duration = 0.1)
-
- /**
- * Terminates this actor system in an asynchronous fashion.
- *
- * This will stop the root actor and in turn will recursively stop all its child actors.
- */
- 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/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behavior.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behavior.kt
index 9ad7f83f..1116c447 100644
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behavior.kt
+++ b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behavior.kt
@@ -1,7 +1,7 @@
/*
* MIT License
*
- * Copyright (c) 2018 atlarge-research
+ * Copyright (c) 2020 atlarge-research
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,169 +25,6 @@
package com.atlarge.odcsim
/**
- * The representation of the behavior of an actor.
- *
- * Behavior can be formulated using factory methods on the companion object or by extending either [DeferredBehavior] or
- * [ReceivingBehavior].
- *
- * Users are advised not to close over [ActorContext] within [Behavior], as it will causes it to become immobile,
- * meaning it cannot be moved to another context and executed there, and therefore it cannot be replicated or forked
- * either.
- *
- * @param T The shape of the messages the behavior accepts.
- */
-sealed class Behavior<T : Any> {
- /**
- * Narrow the type of this behavior.
- *
- * This is almost always a safe operation, but might cause [ClassCastException] in case a narrowed behavior sends
- * messages of a different type to itself and is chained via [Behavior.orElse].
- */
- fun <U : T> narrow(): Behavior<U> = unsafeCast()
-
- /**
- * Widen the type of this behavior by placing a funnel in front of it.
- *
- * @param transform The mapping from the widened type to the original type, returning `null` in-case the message
- * should not be handled.
- */
- fun <U : Any> widen(transform: (U) -> T?): Behavior<U> {
- return wrap(this) { interpreter ->
- receive<U> { ctx, msg ->
- val res = transform(msg)
- @Suppress("UNCHECKED_CAST")
- if (res == null || interpreter.interpretMessage(ctx as ActorContext<T>, res))
- unhandled()
- else
- interpreter.behavior.unsafeCast()
- }.unsafeCast()
- }.unsafeCast()
- }
-
- /**
- * Compose this [Behavior] with a fallback [Behavior] which is used in case this [Behavior] does not handle the
- * incoming message or signal.
- *
- * @param that The fallback behavior.
- */
- fun orElse(that: Behavior<T>): Behavior<T> =
- wrap(this) { left ->
- wrap(that) { right ->
- object : ReceivingBehavior<T>() {
- override fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> {
- if (left.interpretMessage(ctx, msg)) {
- return left.behavior
- } else if (right.interpretMessage(ctx, msg)) {
- return right.behavior
- }
-
- return unhandled()
- }
-
- override fun receiveSignal(ctx: ActorContext<T>, signal: Signal): Behavior<T> {
- if (left.interpretSignal(ctx, signal)) {
- return left.behavior
- } else if (right.interpretSignal(ctx, signal)) {
- return right.behavior
- }
-
- return unhandled()
- }
- }
- }
- }
-
- /**
- * Unsafe utility method for changing the type accepted by this [Behavior].
- * Be aware that changing the type might result in [ClassCastException], when sending a message to the resulting
- * behavior.
- */
- fun <U : Any> unsafeCast(): Behavior<U> {
- @Suppress("UNCHECKED_CAST")
- return this as Behavior<U>
- }
-}
-
-/**
- * A [Behavior] that defers the construction of the actual [Behavior] until the actor is started in some [ActorContext].
- * If the actor is already started, it will immediately evaluate.
- *
- * @param T The shape of the messages the behavior accepts.
- */
-abstract class DeferredBehavior<T : Any> : Behavior<T>() {
- /**
- * Create a [Behavior] instance in the [specified][ctx] [ActorContext].
- *
- * @param ctx The [ActorContext] in which the behavior runs.
- * @return The actor's next behavior.
- */
- abstract operator fun invoke(ctx: ActorContext<T>): Behavior<T>
-}
-
-/**
- * A [Behavior] that concretely defines how an actor will react to the messages and signals it receives.
- * The message may either be of the type that the actor declares and which is part of the [ActorRef] signature,
- * or it may be a system [Signal] that expresses a lifecycle event of either this actor or one of its child actors.
- *
- * @param T The shape of the messages the behavior accepts.
- */
-abstract class ReceivingBehavior<T : Any> : Behavior<T>() {
- /**
- * Process an incoming message of type [T] and return the actor's next behavior.
- *
- * The returned behavior can in addition to normal behaviors be one of the canned special objects:
- * - returning [stopped] will terminate this Behavior
- * - returning [same] designates to reuse the current Behavior
- * - returning [unhandled] keeps the same Behavior and signals that the message was not yet handled
- *
- * @param ctx The [ActorContext] in which the actor is currently running.
- * @param msg The message that was received.
- */
- open fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> = unhandled()
-
- /**
- * Process an incoming [Signal] and return the actor's next behavior.
- *
- * The returned behavior can in addition to normal behaviors be one of the canned special objects:
- * - returning [stopped] will terminate this Behavior
- * - returning [same] designates to reuse the current Behavior
- * - returning [unhandled] keeps the same Behavior and signals that the message was not yet handled
- *
- * @param ctx The [ActorContext] in which the actor is currently running.
- * @param signal The [Signal] that was received.
- */
- open fun receiveSignal(ctx: ActorContext<T>, signal: Signal): Behavior<T> = unhandled()
-}
-
-/**
- * A flag to indicate whether a [Behavior] instance is still alive.
- */
-val <T : Any> Behavior<T>.isAlive get() = this !is StoppedBehavior
-
-/**
- * A flag to indicate whether the last message/signal went unhandled.
- */
-val <T : Any> Behavior<T>.isUnhandled get() = this is UnhandledBehavior
-
-// The special behaviors are kept in this file as to be able to seal the Behavior class to prevent users from extending
-// it.
-/**
- * A special [Behavior] instance that signals that the actor has stopped.
- */
-internal object StoppedBehavior : Behavior<Any>() {
- override fun toString() = "Stopped"
-}
-
-/**
- * A special [Behavior] object to signal that the actor wants to reuse its previous behavior.
- */
-internal object SameBehavior : Behavior<Nothing>() {
- override fun toString() = "Same"
-}
-
-/**
- * A special [Behavior] object that indicates that the last message or signal was not handled.
+ * The behavior of a logical process defines how the process operates within its environments, represented as coroutine.
*/
-internal object UnhandledBehavior : Behavior<Nothing>() {
- override fun toString() = "Unhandled"
-}
+public typealias Behavior = suspend (ctx: ProcessContext) -> Unit
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behaviors.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behaviors.kt
deleted file mode 100644
index eac254ec..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Behaviors.kt
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-@file:JvmName("Behaviors")
-package com.atlarge.odcsim
-
-import com.atlarge.odcsim.internal.BehaviorInterpreter
-import com.atlarge.odcsim.internal.EmptyBehavior
-import com.atlarge.odcsim.internal.IgnoreBehavior
-import com.atlarge.odcsim.internal.TimerSchedulerImpl
-import com.atlarge.odcsim.internal.sendSignal
-
-/**
- * This [Behavior] is used to signal that this actor shall terminate voluntarily. If this actor has created child actors
- * then these will be stopped as part of the shutdown procedure.
- */
-fun <T : Any> stopped(): Behavior<T> = StoppedBehavior.unsafeCast()
-
-/**
- * This [Behavior] is used to signal that this actor wants to reuse its previous behavior.
- */
-fun <T : Any> same(): Behavior<T> = SameBehavior.unsafeCast()
-
-/**
- * This [Behavior] is used to signal to the system that the last message or signal went unhandled. This will
- * reuse the previous behavior.
- */
-fun <T : Any> unhandled(): Behavior<T> = UnhandledBehavior.unsafeCast()
-
-/**
- * A factory for [Behavior]. Creation of the behavior instance is deferred until the actor is started.
- */
-fun <T : Any> setup(block: (ActorContext<T>) -> Behavior<T>): Behavior<T> {
- return object : DeferredBehavior<T>() {
- override fun invoke(ctx: ActorContext<T>): Behavior<T> = block(ctx)
- }
-}
-
-/**
- * A [Behavior] that ignores any incoming message or signal and keeps the same behavior.
- */
-fun <T : Any> ignore(): Behavior<T> = IgnoreBehavior.narrow()
-
-/**
- * A [Behavior] that treats every incoming message or signal as unhandled.
- */
-fun <T : Any> empty(): Behavior<T> = EmptyBehavior.narrow()
-
-/**
- * Construct a [Behavior] that reacts to incoming messages, provides access to the [ActorContext] and returns the
- * actor's next behavior.
- */
-fun <T : Any> receive(handler: (ActorContext<T>, T) -> Behavior<T>): Behavior<T> {
- return object : ReceivingBehavior<T>() {
- override fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> = handler(ctx, msg)
- }
-}
-
-/**
- * Construct a [Behavior] that reacts to incoming messages of type [U], provides access to the [ActorContext] and
- * returns the actor's next behavior. Other messages will be unhandled.
- */
-inline fun <T : Any, reified U : T> receiveOf(crossinline handler: (ActorContext<T>, U) -> Behavior<T>): Behavior<T> {
- return object : ReceivingBehavior<T>() {
- override fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> {
- return if (msg is U)
- handler(ctx, msg)
- else
- unhandled()
- }
- }
-}
-
-/**
- * Construct a [Behavior] that reacts to incoming messages and returns the actor's next behavior.
- */
-fun <T : Any> receiveMessage(handler: (T) -> Behavior<T>): Behavior<T> {
- return object : ReceivingBehavior<T>() {
- override fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> = handler(msg)
- }
-}
-
-/**
- * Construct a [Behavior] that reacts to incoming signals, provides access to the [ActorContext] and returns the
- * actor's next behavior.
- */
-fun <T : Any> receiveSignal(handler: (ActorContext<T>, Signal) -> Behavior<T>): Behavior<T> {
- return object : ReceivingBehavior<T>() {
- override fun receiveSignal(ctx: ActorContext<T>, signal: Signal): Behavior<T> = handler(ctx, signal)
- }
-}
-
-/**
- * Construct a [Behavior] that wraps another behavior instance and uses a [BehaviorInterpreter] to pass incoming
- * messages and signals to the wrapper behavior.
- */
-fun <T : Any> wrap(behavior: Behavior<T>, wrap: (BehaviorInterpreter<T>) -> Behavior<T>): Behavior<T> {
- return setup { ctx -> wrap(BehaviorInterpreter(behavior, ctx)) }
-}
-
-/**
- * Obtain a [TimerScheduler] for building a [Behavior] instance.
- */
-fun <T : Any> withTimers(handler: (TimerScheduler<T>) -> Behavior<T>): Behavior<T> {
- return setup { ctx ->
- val scheduler = TimerSchedulerImpl(ctx)
- receiveSignal<T> { _, signal ->
- if (signal is TimerSchedulerImpl.TimerSignal) {
- val res = scheduler.interceptTimerSignal(signal)
- if (res != null) {
- ctx.send(ctx.self, res)
- return@receiveSignal same()
- }
- }
- unhandled()
- }.join(handler(scheduler))
- }
-}
-
-/**
- * Construct a [Behavior] that waits for the specified duration before constructing the next behavior.
- *
- * @param after The delay before constructing the next behavior.
- * @param handler The handler to construct the behavior with.
- */
-fun <T : Any> withTimeout(after: Duration, handler: (ActorContext<T>) -> Behavior<T>): Behavior<T> =
- setup { ctx ->
- val target = Any()
- ctx.sendSignal(ctx.self, Timeout(target), after)
- receiveSignal { _, signal ->
- if (signal is Timeout && signal.target == target) {
- handler(ctx)
- } else {
- unhandled()
- }
- }
- }
-
-/**
- * Join together both [Behavior] with another [Behavior], essentially running them side-by-side, only directly
- * propagating stopped behavior.
- *
- * @param that The behavior to join with.
- */
-fun <T : Any> Behavior<T>.join(that: Behavior<T>): Behavior<T> =
- wrap(this) { left ->
- wrap(that) { right ->
- object : ReceivingBehavior<T>() {
- override fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> {
- if (left.interpretMessage(ctx, msg)) {
- return left.propagate(this) // Propagate stopped behavior
- } else if (right.interpretMessage(ctx, msg)) {
- return right.propagate(this)
- }
-
- return unhandled()
- }
-
- override fun receiveSignal(ctx: ActorContext<T>, signal: Signal): Behavior<T> {
- if (left.interpretSignal(ctx, signal)) {
- return left.propagate(this)
- } else if (right.interpretSignal(ctx, signal)) {
- return right.propagate(this)
- }
-
- return unhandled()
- }
- }
- }
- }
-
-/**
- * Widen the type of messages the [Behavior] by marking all other messages as unhandled.
- */
-inline fun <U : Any, reified T : U> Behavior<T>.widen(): Behavior<U> = widen {
- if (it is T)
- it
- else
- null
-}
-
-/**
- * Keep the specified [Behavior] alive if it returns the stopped behavior.
- */
-fun <T : Any> Behavior<T>.keepAlive(): Behavior<T> =
- wrap(this) { interpreter ->
- object : ReceivingBehavior<T>() {
- override fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> {
- if (interpreter.interpretMessage(ctx, msg)) {
- return this
- }
- return empty()
- }
-
- override fun receiveSignal(ctx: ActorContext<T>, signal: Signal): Behavior<T> {
- if (interpreter.interpretSignal(ctx, signal)) {
- return this
- }
-
- return empty()
- }
- }
- }
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Channel.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Channel.kt
new file mode 100644
index 00000000..10b4908a
--- /dev/null
+++ b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Channel.kt
@@ -0,0 +1,70 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.odcsim
+
+import java.io.Serializable
+
+/**
+ * A unidirectional communication medium using message passing. Processes may send messages over a channel, and
+ * another process is able to receive messages sent over a channel it has a reference to (in form of a [ReceivePort]).
+ *
+ * Channels are represented by their send and receive endpoints at which processes may respectively send and receive
+ * messages from this channel.
+ *
+ * Channels and their respective send and receive references may be shared freely between logical processes in the same
+ * simulation.
+ */
+public interface Channel<T : Any> : Serializable {
+ /**
+ * The endpoint of the channel processes may use to send messages to.
+ */
+ public val send: SendRef<T>
+
+ /**
+ * The endpoint of the channel processes may receive messages from.
+ */
+ public val receive: ReceiveRef<T>
+
+ /**
+ * Obtain the send endpoint of the channel when unpacking the channel. See [send].
+ */
+ public operator fun component1(): SendRef<T> = send
+
+ /**
+ * Obtain the receive endpoint of the channel when unpacking the channel. See [receive].
+ */
+ public operator fun component2(): ReceiveRef<T> = receive
+}
+
+/**
+ * An opaque object representing a [Channel] endpoint through which logical processes can send messages over the
+ * channel.
+ */
+public interface SendRef<in T : Any> : Serializable
+
+/**
+ * An opaque object representing the receive endpoint of a [Channel].
+ */
+public interface ReceiveRef<out T : Any> : Serializable
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Envelope.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Envelope.kt
deleted file mode 100644
index 3b73d52d..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Envelope.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim
-
-import java.io.Serializable
-
-/**
- * A timestamped wrapper for messages that will be delivered to an actor.
- */
-interface Envelope<T : Any> : Comparable<Envelope<*>>, Serializable {
- /**
- * The time at which this message should be delivered.
- */
- val time: Instant
-
- /**
- * The message contained in this envelope, of type [T]
- */
- val message: T
-
- /**
- * Extract the delivery time from the envelope.
- */
- operator fun component1(): Instant = time
-
- /**
- * Extract the message from this envelope.
- */
- operator fun component2(): T = message
-
- /**
- * Compare this envelope to the [other] envelope, ordered increasingly in time.
- */
- override fun compareTo(other: Envelope<*>): Int = time.compareTo(other.time)
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Port.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Port.kt
new file mode 100644
index 00000000..30d4790c
--- /dev/null
+++ b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Port.kt
@@ -0,0 +1,64 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.odcsim
+
+/**
+ * A communication endpoint of a specific logical process through which messages pass.
+ *
+ * Ports are tied to a specific logical process and may not be shared with other processes. Doing so results in
+ * undefined behavior and might cause violation of time-consistency between processes.
+ */
+public interface Port {
+ /**
+ * Close this communication endpoint. This informs the process(es) at the other end of the port that the caller
+ * will not send or receive messages via this port.
+ *
+ * This is an idempotent operation – subsequent invocations of this function have no effect and return `false`.
+ */
+ fun close(): Boolean
+}
+
+/**
+ * A [Port] through which a logical process may receive messages from other [SendPort]s.
+ */
+public interface ReceivePort<out T : Any> : Port {
+ /**
+ * Receive a message send to this port or suspend the caller while no messages have been received at this port yet.
+ */
+ public suspend fun receive(): T
+}
+
+/**
+ * A [Port] through which logical processes may send messages to a [ReceivePort].
+ */
+public interface SendPort<in T : Any> : Port {
+ /**
+ * Send a message via this port to the process(es) listening at the other end of the port.
+ *
+ * Messages are send asynchronously to the receivers and do not suspend the caller. This method guarantees
+ * exactly-once delivery while respecting time-consistency between owner of the send port and its receivers.
+ */
+ public fun send(message: T)
+}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ProcessContext.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ProcessContext.kt
new file mode 100644
index 00000000..2a72e331
--- /dev/null
+++ b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ProcessContext.kt
@@ -0,0 +1,82 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.odcsim
+
+import java.time.Clock
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.coroutineContext
+
+/**
+ * Represents the execution context of a logical process in simulation.
+ */
+public interface ProcessContext : CoroutineContext.Element {
+ /**
+ * Key for [ProcessContext] instance in the coroutine context.
+ */
+ companion object Key : CoroutineContext.Key<ProcessContext>
+
+ /**
+ * The reference to the logical process of this context.
+ */
+ public val self: ProcessRef
+
+ /**
+ * The clock tracking the simulation time.
+ */
+ public val clock: Clock
+
+ /**
+ * Spawn an anonymous logical process in the simulation universe with the specified [behavior].
+ */
+ public fun spawn(behavior: Behavior): ProcessRef
+
+ /**
+ * Spawn a logical process in the simulation universe with the specified [behavior] and [name].
+ */
+ public fun spawn(behavior: Behavior, name: String): ProcessRef
+
+ /**
+ * Open a new communication [Channel] for messages of type [T].
+ */
+ public fun <T : Any> open(): Channel<T>
+
+ /**
+ * Create a [SendPort] for sending messages to the specified [send].
+ */
+ public suspend fun <T : Any> connect(send: SendRef<T>): SendPort<T>
+
+ /**
+ * Create a [ReceivePort] for listening to the messages sent to the specified [receive] endpoint of a channel.
+ */
+ public suspend fun <T : Any> listen(receive: ReceiveRef<T>): ReceivePort<T>
+}
+
+/**
+ * The process context of the current coroutine.
+ */
+@Suppress("WRONG_MODIFIER_TARGET")
+public suspend inline val processContext: ProcessContext
+ @Suppress("ILLEGAL_SUSPEND_PROPERTY_ACCESS")
+ get() = coroutineContext[ProcessContext.Key] ?: throw IllegalStateException("No process context active")
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/dsl/Timeout.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ProcessRef.kt
index 16b6f534..833458e4 100644
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/dsl/Timeout.kt
+++ b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ProcessRef.kt
@@ -1,7 +1,7 @@
/*
* MIT License
*
- * Copyright (c) 2018 atlarge-research
+ * Copyright (c) 2020 atlarge-research
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,21 +22,24 @@
* SOFTWARE.
*/
-package com.atlarge.odcsim.coroutines.dsl
+package com.atlarge.odcsim
-import com.atlarge.odcsim.Duration
-import com.atlarge.odcsim.coroutines.suspendWithBehavior
-import com.atlarge.odcsim.withTimeout
-import kotlin.coroutines.resume
+import java.io.Serializable
/**
- * Block execution for the specified duration.
- *
- * @param after The duration after which execution should continue.
+ * A reference to a logical process in simulation.
*/
-suspend fun timeout(after: Duration) = suspendWithBehavior<Any, Unit> { cont, next ->
- withTimeout(after) {
- cont.resume(Unit)
- next()
- }
+public interface ProcessRef : Comparable<ProcessRef>, Serializable {
+ /**
+ * The name of the process.
+ */
+ public val name: String
+
+ /**
+ * Compare [other] process ref with this process reference for order.
+ *
+ * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater
+ * than the specified path.
+ */
+ override fun compareTo(other: ProcessRef): Int = name.compareTo(other.name)
}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Signals.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Signals.kt
deleted file mode 100644
index 9b707348..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Signals.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim
-
-/**
- * System signals are notifications that are generated by the system and delivered to the actor behavior in a reliable
- * fashion.
- */
-interface Signal
-
-/**
- * Lifecycle signal that is fired upon creation of the actor. This will be the first message that the actor receives.
- */
-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
- * are waiting on this signal.
- *
- * @property target The target object that has timed out.
- */
-data class Timeout(val target: Any) : Signal
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorRef.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngine.kt
index 45fc756e..e35acbf0 100644
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorRef.kt
+++ b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngine.kt
@@ -24,27 +24,25 @@
package com.atlarge.odcsim
-import java.io.Serializable
-
/**
- * A reference to an entity in simulation that accepts messages of type [T].
+ * An engine for managing logical processes represented as [Behavior] during simulation.
+ *
+ * An implementation of this interface should be provided by an engine. See for example *odcsim-engine-omega*,
+ * which is the reference implementation of the *odcsim* API.
*/
-interface ActorRef<in T : Any> : Comparable<ActorRef<*>>, Serializable {
+public interface SimulationEngine {
/**
- * The path for this actor (from this actor up to the root actor).
+ * The name of this engine instance, used to distinguish between multiple engines running within the same JVM.
*/
- val path: ActorPath
+ public val name: String
/**
- * Compare this reference to another actor reference.
+ * Run the simulation.
*/
- override fun compareTo(other: ActorRef<*>): Int = path.compareTo(other.path)
-}
+ public suspend fun run()
-/**
- * Unsafe helper method for widening the type accepted by this [ActorRef].
- */
-fun <U : Any, T : U> ActorRef<T>.unsafeCast(): ActorRef<U> {
- @Suppress("UNCHECKED_CAST")
- return this as ActorRef<U>
+ /**
+ * Terminates this engine in an asynchronous fashion.
+ */
+ public suspend fun terminate()
}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorSystemFactory.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngineProvider.kt
index f59bc966..93dda963 100644
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/ActorSystemFactory.kt
+++ b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngineProvider.kt
@@ -25,14 +25,14 @@
package com.atlarge.odcsim
/**
- * A factory for [ActorSystem] instances that allows users to dynamically load engine implementations.
+ * A factory for [SimulationEngine] instances that allows users to dynamically load engine implementations.
*/
-interface ActorSystemFactory {
+public interface SimulationEngineProvider {
/**
- * Create an [ActorSystem] with the given root [Behavior] and the given name.
+ * Create an [SimulationEngine] with the given root [Behavior] and the given name.
*
- * @param root The behavior of the root actor.
+ * @param root The behavior of the root process.
* @param name The name of the engine instance.
*/
- operator fun <T : Any> invoke(root: Behavior<T>, name: String): ActorSystem<T>
+ public operator fun invoke(root: Behavior, name: String): SimulationEngine
}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/StashBuffer.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/StashBuffer.kt
deleted file mode 100644
index 5d73d808..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/StashBuffer.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim
-
-import com.atlarge.odcsim.internal.StashBufferImpl
-
-/**
- * A non thread safe mutable message buffer that can be used to buffer messages inside actors and then unstash them.
- *
- * @param T The shape of the messages in this buffer.
- */
-interface StashBuffer<T : Any> {
- /**
- * The first element of the buffer.
- *
- * @throws NoSuchElementException if the buffer is empty.
- */
- val head: T
-
- /**
- * A flag to indicate whether the buffer is empty.
- */
- val isEmpty: Boolean
-
- /**
- * A flag to indicate whether the buffer is full.
- */
- val isFull: Boolean
-
- /**
- * The number of elements in the stash buffer.
- */
- val size: Int
-
- /**
- * Iterate over all elements of the buffer and apply a function to each element, without removing them.
- *
- * @param block The function to invoke for each element.
- */
- fun forEach(block: (T) -> Unit)
-
- /**
- * Add one element to the end of the message buffer.
- *
- * @param msg The message to stash.
- * @throws IllegalStateException if the element cannot be added at this time due to capacity restrictions
- */
- fun stash(msg: T)
-
- /**
- * Process all stashed messages with the behavior and the returned [Behavior] from each processed message.
- *
- * @param ctx The actor context to process these messages in.
- * @param behavior The behavior to process the messages with.
- */
- fun unstashAll(ctx: ActorContext<T>, behavior: Behavior<T>): Behavior<T>
-
- companion object {
- /**
- * Construct a [StashBuffer] with the specified [capacity].
- *
- * @param capacity The capacity of the buffer.
- */
- operator fun <T : Any> invoke(capacity: Int): StashBuffer<T> = StashBufferImpl(capacity)
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Time.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Time.kt
deleted file mode 100644
index f19f6fe2..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Time.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim
-
-/**
- * An instantaneous point on the time-line, used to record message time-stamps in a simulation.
- */
-typealias Instant = Double
-
-/**
- * A time interval which represents the amount of elapsed time between two messages.
- */
-typealias Duration = Double
-
-/**
- * Convert this [Int] into an [Instant].
- */
-fun Int.toInstant(): Instant = toDouble()
-
-/**
- * Convert this [Int] into a [Duration].
- */
-fun Int.toDuration(): Duration = toDouble()
-
-/**
- * Convert this [Long] into an [Instant].
- */
-fun Long.toInstant(): Instant = toDouble()
-
-/**
- * Convert this [Long] into a [Duration].
- */
-fun Long.toDuration(): Duration = toDouble()
-
-/**
- * Convert this [Float] into an [Instant].
- */
-fun Float.toInstant(): Instant = toDouble()
-
-/**
- * Convert this [Float] into a [Duration].
- */
-fun Float.toDuration(): Duration = toDouble()
-
-/**
- * Convert this [Double] into an [Instant].
- */
-fun Double.toInstant(): Instant = toDouble()
-
-/**
- * Convert this [Double] into a [Duration].
- */
-fun Double.toDuration(): Duration = toDouble()
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/TimerScheduler.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/TimerScheduler.kt
deleted file mode 100644
index c5c54b64..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/TimerScheduler.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim
-
-/**
- * An interface to provide support for scheduled self messages in an actor. It is used with [withTimers].
- * Timers are bound to the lifecycle of the actor that owns it, and thus are cancelled automatically when it is
- * restarted or stopped.
- *
- * Please be aware that [TimerScheduler] is not thread-safe and must only be used within the actor that owns it.
- *
- * @param T The shape of the messages the owning actor of this scheduling accepts.
- */
-interface TimerScheduler<T : Any> {
- /**
- * Cancel a timer with the given key.
- *
- * @param key The key of the timer.
- */
- fun cancel(key: Any)
-
- /**
- * Cancel all timers.
- */
- fun cancelAll()
-
- /**
- * Check if a timer with a given [key] is active.
- *
- * @param key The key to check if it is active.
- * @return `true` if a timer with the specified key is active, `false` otherwise.
- */
- fun isTimerActive(key: Any): Boolean
-
- /**
- * Start a periodic timer that will send [msg] to the `self` actor at a fixed [interval].
- *
- * @param key The key of the timer.
- * @param msg The message to send to the actor.
- * @param interval The interval of simulation time after which it should be sent.
- */
- fun startPeriodicTimer(key: Any, msg: T, interval: Duration)
-
- /**
- * Start a timer that will send [msg] once to the `self` actor after the given [delay].
- *
- * @param key The key of the timer.
- * @param msg The message to send to the actor.
- * @param delay The delay in simulation time after which it should be sent.
- */
- fun startSingleTimer(key: Any, msg: T, delay: Duration)
-
- /**
- * Run [block] periodically at a fixed [interval]
- *
- * @param key The key of the timer.
- * @param interval The delay of simulation time after which the block should run.
- * @param block The block to run.
- */
- fun every(key: Any, interval: Duration, block: () -> Unit)
-
- /**
- * Run [block] after the specified [delay].
- *
- * @param key The key of the timer.
- * @param delay The delay in simulation time after which the block should run.
- * @param block The block to run.
- */
- fun after(key: Any, delay: Duration, block: () -> Unit)
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt
deleted file mode 100644
index eb26add1..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/Behavior.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.coroutines
-
-import com.atlarge.odcsim.ActorContext
-import com.atlarge.odcsim.Behavior
-import com.atlarge.odcsim.DeferredBehavior
-import com.atlarge.odcsim.Signal
-import com.atlarge.odcsim.internal.SuspendingActorContextImpl
-import com.atlarge.odcsim.internal.SuspendingBehaviorImpl
-import kotlin.coroutines.Continuation
-import kotlin.coroutines.CoroutineContext
-import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
-import kotlin.coroutines.suspendCoroutine
-
-/**
- * A [Behavior] that allows method calls to suspend execution via Kotlin coroutines.
- *
- * @param T The shape of the messages the actor accepts.
- */
-abstract class SuspendingBehavior<T : Any> : DeferredBehavior<T>() {
- /**
- * Run the suspending logic of this behavior.
- *
- * @param ctx The [SuspendingActorContext] in which the behavior is executed.
- * @return The next behavior for the actor.
- */
- abstract suspend operator fun invoke(ctx: SuspendingActorContext<T>): Behavior<T>
-
- // Immediately transfer to implementation
- override fun invoke(ctx: ActorContext<T>): Behavior<T> = SuspendingBehaviorImpl(ctx, this).start()
-}
-
-/**
- * An [ActorContext] that provides additional functionality for receiving messages and signals from
- * the actor's mailbox.
- *
- * @param T The shape of the messages the actor accepts.
- */
-interface SuspendingActorContext<T : Any> : ActorContext<T>, CoroutineContext.Element {
- /**
- * Suspend execution of the active coroutine to wait for a message of type [T] to be received in the actor's
- * mailbox. During suspension, incoming signals will be marked unhandled.
- *
- * @return The message of type [T] that has been received.
- */
- suspend fun receive(): T
-
- /**
- * Suspend execution of the active coroutine to wait for a [Signal] to be received in the actor's mailbox.
- * During suspension, incoming messages will be marked unhandled.
- *
- * @return The [Signal] that has been received.
- */
- suspend fun receiveSignal(): Signal
-
- /**
- * A key to provide access to the untyped [SuspendingActorContext] via [CoroutineContext] for suspending methods
- * running inside a [SuspendingBehavior].
- */
- companion object Key : CoroutineContext.Key<SuspendingActorContext<*>>
-}
-
-/**
- * Obtains the current continuation instance inside suspend functions and suspends currently running coroutine. [block]
- * should return a [Behavior] that will resume the continuation and return the next behavior which is supplied via the
- * second argument of the block.
- */
-suspend fun <T : Any, U> suspendWithBehavior(block: (Continuation<U>, () -> Behavior<T>) -> Behavior<T>): U =
- suspendCoroutine { cont ->
- @Suppress("UNCHECKED_CAST")
- val ctx = cont.context[SuspendingActorContext] as? SuspendingActorContextImpl<T>
- ?: throw UnsupportedOperationException("Coroutine does not run inside SuspendingBehavior")
- ctx.become(block(cont) { ctx.behavior })
- }
-
-/**
- * Obtain the current [SuspendingActorContext] instance for the active continuation.
- */
-suspend fun <T : Any> actorContext(): SuspendingActorContext<T> =
- suspendCoroutineUninterceptedOrReturn { cont ->
- @Suppress("UNCHECKED_CAST")
- cont.context[SuspendingActorContext] as? SuspendingActorContext<T>
- ?: throw UnsupportedOperationException("Coroutine does not run inside SuspendingBehavior")
- }
-
-/**
- * Construct a [Behavior] that uses Kotlin coroutines functionality to handle incoming messages and signals.
- */
-fun <T : Any> suspending(block: suspend (SuspendingActorContext<T>) -> Behavior<T>): Behavior<T> {
- return object : SuspendingBehavior<T>() {
- override suspend fun invoke(ctx: SuspendingActorContext<T>) = block(ctx)
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/dsl/Receive.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/dsl/Receive.kt
deleted file mode 100644
index e995c0e3..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/coroutines/dsl/Receive.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.coroutines.dsl
-
-import com.atlarge.odcsim.ActorRef
-import com.atlarge.odcsim.Duration
-import com.atlarge.odcsim.coroutines.SuspendingActorContext
-import com.atlarge.odcsim.coroutines.suspendWithBehavior
-import com.atlarge.odcsim.receiveMessage
-import com.atlarge.odcsim.unhandled
-import kotlin.coroutines.resume
-
-/**
- * Receive only messages of type [U] and mark all other messages as unhandled.
- *
- * @return The received message.
- */
-suspend inline fun <T : Any, reified U : T> SuspendingActorContext<T>.receiveOf(): U =
- suspendWithBehavior<T, U> { cont, next ->
- receiveMessage { msg ->
- if (msg is U) {
- cont.resume(msg)
- next()
- } else {
- unhandled()
- }
- }
- }
-
-/**
- * Send the specified message to the given reference and wait for a reply.
- *
- * @param ref The actor to send the message to.
- * @param after The delay after which the message should be received by the actor.
- * @param transform The block to transform `self` to a message.
- */
-suspend inline fun <T : Any, U : Any, reified V : T> SuspendingActorContext<T>.ask(
- ref: ActorRef<U>,
- after: Duration = 0.0,
- transform: (ActorRef<T>) -> U
-): V {
- send(ref, transform(self), after)
- return receiveOf()
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/ActorContext.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/ActorContext.kt
deleted file mode 100644
index f1aba25e..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/ActorContext.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal
-
-import com.atlarge.odcsim.ActorContext
-import com.atlarge.odcsim.ActorRef
-import com.atlarge.odcsim.Duration
-import com.atlarge.odcsim.Signal
-
-/**
- * Send the specified [Signal] to the given actor reference after the specified duration.
- *
- * @param ref The actor to send the signal to.
- * @param signal The signal to send to the referenced actor.
- * @param after The delay after which the signal should be received by the actor.
- */
-fun ActorContext<*>.sendSignal(ref: ActorRef<*>, signal: Signal, after: Duration = 0.0) {
- // Signals are currently processed as regular messages
- @Suppress("UNCHECKED_CAST")
- send(ref as ActorRef<Any>, signal, after)
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/Behavior.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/Behavior.kt
deleted file mode 100644
index b07cabc0..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/Behavior.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal
-
-import com.atlarge.odcsim.ActorContext
-import com.atlarge.odcsim.Behavior
-import com.atlarge.odcsim.ReceivingBehavior
-import com.atlarge.odcsim.Signal
-
-/**
- * A [Behavior] object that ignores all messages sent to the actor.
- */
-internal object IgnoreBehavior : ReceivingBehavior<Any>() {
- override fun receive(ctx: ActorContext<Any>, msg: Any): Behavior<Any> = this
-
- override fun receiveSignal(ctx: ActorContext<Any>, signal: Signal): Behavior<Any> = this
-
- override fun toString() = "Ignore"
-}
-
-/**
- * A [Behavior] object that does not handle any message it receives.
- */
-internal object EmptyBehavior : ReceivingBehavior<Any>() {
- override fun toString() = "Empty"
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/BehaviorInterpreter.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/BehaviorInterpreter.kt
deleted file mode 100644
index 194c2a62..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/BehaviorInterpreter.kt
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal
-
-import com.atlarge.odcsim.ActorContext
-import com.atlarge.odcsim.Behavior
-import com.atlarge.odcsim.DeferredBehavior
-import com.atlarge.odcsim.ReceivingBehavior
-import com.atlarge.odcsim.SameBehavior
-import com.atlarge.odcsim.Signal
-import com.atlarge.odcsim.StoppedBehavior
-import com.atlarge.odcsim.UnhandledBehavior
-import com.atlarge.odcsim.isAlive
-import com.atlarge.odcsim.isUnhandled
-
-/**
- * Helper class that interprets messages/signals, canonicalizes special objects and manages the life-cycle of
- * [Behavior] instances.
- *
- * @param initialBehavior The initial behavior to use.
- */
-class BehaviorInterpreter<T : Any>(initialBehavior: Behavior<T>) {
- /**
- * The current [Behavior] instance.
- */
- var behavior: Behavior<T> = initialBehavior
- private set
-
- /**
- * A flag to indicate the interpreter is still alive.
- */
- val isAlive: Boolean get() = behavior.isAlive
-
- /**
- * Construct a [BehaviorInterpreter] with the specified initial behavior and immediately start it in the specified
- * context.
- *
- * @param initialBehavior The initial behavior of the actor.
- * @param ctx The [ActorContext] to run the behavior in.
- */
- constructor(initialBehavior: Behavior<T>, ctx: ActorContext<T>) : this(initialBehavior) {
- start(ctx)
- }
-
- /**
- * Start the initial behavior.
- *
- * @param ctx The [ActorContext] to start the behavior in.
- */
- fun start(ctx: ActorContext<T>) {
- behavior = validateAsInitial(start(ctx, behavior))
- }
-
- /**
- * Stop the current active behavior and move into the stopped state.
- *
- * @param ctx The [ActorContext] this takes place in.
- */
- fun stop(ctx: ActorContext<T>) {
- behavior = start(ctx, StoppedBehavior.narrow())
- }
-
- /**
- * Replace the current behavior with the specified new behavior.
- *
- * @param ctx The [ActorContext] to run the behavior in.
- * @param next The behavior to replace the current behavior with.
- */
- fun become(ctx: ActorContext<T>, next: Behavior<T>) {
- this.behavior = canonicalize(ctx, behavior, next)
- }
-
- /**
- * Propagate special states of the wrapper [Behavior] to the specified [Behavior]. This means
- * that if the behavior of this interpreter is stopped or unhandled, this will be propagated.
- *
- * @param behavior The [Behavior] to map.
- * @return Either the specified [Behavior] or the propagated special objects.
- */
- fun propagate(behavior: Behavior<T>): Behavior<T> =
- if (this.behavior.isUnhandled || !this.behavior.isAlive)
- this.behavior
- else
- behavior
-
- /**
- * Interpret the given message of type [T] using the current active behavior.
- *
- * @return `true` if the message was handled by the active behavior, `false` otherwise.
- */
- fun interpretMessage(ctx: ActorContext<T>, msg: T): Boolean = interpret(ctx, msg, false)
-
- /**
- * Interpret the given [Signal] using the current active behavior.
- *
- * @return `true` if the signal was handled by the active behavior, `false` otherwise.
- */
- fun interpretSignal(ctx: ActorContext<T>, signal: Signal): Boolean = interpret(ctx, signal, true)
-
- /**
- * Interpret the given message or signal using the current active behavior.
- *
- * @return `true` if the message or signal was handled by the active behavior, `false` otherwise.
- */
- private fun interpret(ctx: ActorContext<T>, msg: Any, isSignal: Boolean): Boolean =
- if (isAlive) {
- val next = when (val current = behavior) {
- is DeferredBehavior<T> ->
- throw IllegalStateException("Deferred [$current] should not be passed to interpreter")
- is ReceivingBehavior<T> ->
- if (isSignal)
- current.receiveSignal(ctx, msg as Signal)
- else
- @Suppress("UNCHECKED_CAST")
- current.receive(ctx, msg as T)
- is SameBehavior, is UnhandledBehavior ->
- throw IllegalStateException("Cannot execute with [$current] as behavior")
- is StoppedBehavior -> current
- }
-
- val unhandled = next.isUnhandled
- behavior = canonicalize(ctx, behavior, next)
- !unhandled
- } else {
- false
- }
-
- /**
- * Validate whether the given [Behavior] can be used as initial behavior. Throw an [IllegalArgumentException] if
- * the [Behavior] is not valid.
- *
- * @param behavior The behavior to validate.
- */
- private fun validateAsInitial(behavior: Behavior<T>): Behavior<T> =
- when (behavior) {
- is SameBehavior, is UnhandledBehavior ->
- throw IllegalArgumentException("Cannot use [$behavior] as initial behavior")
- else -> behavior
- }
-
- /**
- * Helper methods to properly manage the special, canned behavior objects. It highly recommended to use the
- * [BehaviorInterpreter] instead to properly manage the life-cycles of the behavior objects.
- */
- companion object {
- /**
- * Start the initial behavior of an actor in the specified [ActorContext].
- *
- * This will activate the initial behavior and canonicalize the resulting behavior.
- *
- * @param ctx The [ActorContext] to start the behavior in.
- * @param behavior The initial behavior to start.
- * @return The behavior that has been started.
- */
- tailrec fun <T : Any> start(ctx: ActorContext<T>, behavior: Behavior<T>): Behavior<T> =
- when (behavior) {
- is DeferredBehavior<T> -> start(ctx, behavior(ctx))
- else -> behavior
- }
-
- /**
- * Given a possibly special behavior (same or unhandled) and a "current" behavior (which defines the meaning of
- * encountering a `same` behavior) this method computes the next behavior, suitable for passing a message or
- * signal.
- *
- * @param ctx The context in which the actor runs.
- * @param current The actor's current behavior.
- * @param next The actor's next behavior.
- * @return The actor's canonicalized next behavior.
- */
- tailrec fun <T : Any> canonicalize(ctx: ActorContext<T>, current: Behavior<T>, next: Behavior<T>): Behavior<T> =
- when (next) {
- is SameBehavior, current -> current
- is UnhandledBehavior -> current
- is DeferredBehavior<T> -> canonicalize(ctx, current, next(ctx))
- else -> next
- }
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt
deleted file mode 100644
index c3346bdf..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2018 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal
-
-import com.atlarge.odcsim.ActorContext
-import com.atlarge.odcsim.ActorRef
-import com.atlarge.odcsim.ActorSystem
-import com.atlarge.odcsim.Behavior
-import com.atlarge.odcsim.Duration
-import com.atlarge.odcsim.Instant
-import com.atlarge.odcsim.ReceivingBehavior
-import com.atlarge.odcsim.Signal
-import com.atlarge.odcsim.coroutines.SuspendingActorContext
-import com.atlarge.odcsim.coroutines.SuspendingBehavior
-import com.atlarge.odcsim.coroutines.suspendWithBehavior
-import com.atlarge.odcsim.empty
-import com.atlarge.odcsim.receiveMessage
-import com.atlarge.odcsim.receiveSignal
-import kotlin.coroutines.Continuation
-import kotlin.coroutines.CoroutineContext
-import kotlin.coroutines.resume
-import kotlin.coroutines.startCoroutine
-import org.slf4j.Logger
-
-/**
- * This interface exposes internal functionality provided by [SuspendingBehaviorImpl] on [SuspendingActorContext] to
- * control the active behavior of the coroutine.
- */
-interface SuspendingActorContextImpl<T : Any> : SuspendingActorContext<T> {
- /**
- * The current active behavior
- */
- val behavior: Behavior<T>
-
- /**
- * Replace the current active behavior with the specified new behavior.
- *
- * @param next The behavior to replace the current behavior with.
- */
- fun become(next: Behavior<T>)
-}
-
-/**
- * Implementation of [SuspendingBehavior] class that maps the suspending method calls to the [Behavior]
- * interface.
- * This implementation uses the fact that each actor is thread-safe (as it processes its mailbox sequentially).
- */
-internal class SuspendingBehaviorImpl<T : Any>(
- private var actorContext: ActorContext<T>,
- initialBehavior: SuspendingBehavior<T>
-) : ReceivingBehavior<T>(), SuspendingActorContextImpl<T> {
-
- /**
- * The next behavior to use.
- */
- private var next: Behavior<T> = this
-
- /**
- * The [BehaviorInterpreter] to wrap the suspending behavior.
- */
- private val interpreter = BehaviorInterpreter(initialBehavior)
-
- override fun receive(ctx: ActorContext<T>, msg: T): Behavior<T> {
- this.actorContext = ctx
- return interpreter.also { it.interpretMessage(ctx, msg) }.propagate(next)
- }
-
- override fun receiveSignal(ctx: ActorContext<T>, signal: Signal): Behavior<T> {
- this.actorContext = ctx
- return interpreter.also { it.interpretSignal(ctx, signal) }.propagate(next)
- }
-
- override val self: ActorRef<T> get() = actorContext.self
-
- 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<*>) = actorContext.stop(child)
-
- override fun watch(target: ActorRef<*>) = actorContext.watch(target)
-
- override fun unwatch(target: ActorRef<*>) = actorContext.unwatch(target)
-
- override fun sync(target: ActorRef<*>) = actorContext.sync(target)
-
- override fun unsync(target: ActorRef<*>) = actorContext.unsync(target)
-
- override fun isSync(target: ActorRef<*>): Boolean = actorContext.isSync(target)
-
- override suspend fun receive(): T = suspendWithBehavior<T, T> { cont, next ->
- receiveMessage { msg ->
- cont.resume(msg)
- next()
- }
- }
-
- override suspend fun receiveSignal(): Signal = suspendWithBehavior<T, Signal> { cont, next ->
- receiveSignal { _, signal ->
- cont.resume(signal)
- next()
- }
- }
-
- override val behavior: Behavior<T> get() = interpreter.behavior
-
- override fun become(next: Behavior<T>) {
- interpreter.become(actorContext, next)
- }
-
- override val key: CoroutineContext.Key<*> = SuspendingActorContext.Key
-
- /**
- * Start the suspending behavior.
- */
- internal fun start(): Behavior<T> {
- val behavior = interpreter.behavior as SuspendingBehavior<T>
- val block = suspend { behavior(this) }
- interpreter.become(actorContext, empty())
- block.startCoroutine(SuspendingBehaviorImplContinuation())
- return next
- }
-
- /**
- * Stop the suspending behavior.
- */
- private fun stop() {
- this.interpreter.stop(actorContext)
- }
-
- /**
- * The continuation of suspending behavior.
- */
- private inner class SuspendingBehaviorImplContinuation : Continuation<Behavior<T>> {
- override val context = this@SuspendingBehaviorImpl
-
- override fun resumeWith(result: Result<Behavior<T>>) {
- if (result.isSuccess) {
- next = result.getOrNull()!!
- } else if (result.isFailure) {
- throw result.exceptionOrNull()!!
- }
- }
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/StashBufferImpl.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/StashBufferImpl.kt
deleted file mode 100644
index 24c3a9d5..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/StashBufferImpl.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal
-
-import com.atlarge.odcsim.ActorContext
-import com.atlarge.odcsim.Behavior
-import com.atlarge.odcsim.StashBuffer
-import java.util.ArrayDeque
-
-/**
- * Internal implementation of the [StashBuffer] interface.
- */
-internal class StashBufferImpl<T : Any>(private val capacity: Int) : StashBuffer<T> {
- /**
- * The internal queue used to store the messages.
- */
- private val queue = ArrayDeque<T>(capacity)
-
- override val head: T
- get() = queue.first
-
- override val isEmpty: Boolean
- get() = queue.isEmpty()
-
- override val isFull: Boolean
- get() = size > capacity
-
- override val size: Int
- get() = queue.size
-
- override fun forEach(block: (T) -> Unit) {
- queue.toList().forEach(block)
- }
-
- override fun stash(msg: T) {
- queue.add(msg)
- }
-
- override fun unstashAll(ctx: ActorContext<T>, behavior: Behavior<T>): Behavior<T> {
- val messages = queue.toList()
- queue.clear()
-
- val interpreter = BehaviorInterpreter<T>(behavior)
- interpreter.start(ctx)
-
- for (message in messages) {
- interpreter.interpretMessage(ctx, message)
- }
-
- return interpreter.behavior
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/TimerSchedulerImpl.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/TimerSchedulerImpl.kt
deleted file mode 100644
index 22bec507..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/TimerSchedulerImpl.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal
-
-import com.atlarge.odcsim.ActorContext
-import com.atlarge.odcsim.Duration
-import com.atlarge.odcsim.Signal
-import com.atlarge.odcsim.TimerScheduler
-
-/**
- * Implementation of [TimerScheduler] that uses the actor's [ActorContext] to provide timer functionality.
- *
- * @property ctx The actor context to use.
- */
-internal class TimerSchedulerImpl<T : Any>(private val ctx: ActorContext<T>) : TimerScheduler<T> {
- private val timers = mutableMapOf<Any, Timer<T>>()
-
- override fun cancel(key: Any) {
- val timer = timers[key] ?: return
- ctx.log.debug("Cancel timer [{}] with generation [{}]", timer.key, timer.generation)
- timers -= timer.key
- }
-
- override fun cancelAll() {
- ctx.log.debug("Cancel all timers")
- timers.clear()
- }
-
- override fun isTimerActive(key: Any): Boolean = timers.containsKey(key)
-
- override fun startPeriodicTimer(key: Any, msg: T, interval: Duration) {
- startTimer(key, msg, interval, true)
- }
-
- override fun startSingleTimer(key: Any, msg: T, delay: Duration) {
- startTimer(key, msg, delay, false)
- }
-
- override fun every(key: Any, interval: Duration, block: () -> Unit) {
- @Suppress("UNCHECKED_CAST")
- startTimer(key, Block(block) as T, interval, true)
- }
-
- override fun after(key: Any, delay: Duration, block: () -> Unit) {
- @Suppress("UNCHECKED_CAST")
- startTimer(key, Block(block) as T, delay, false)
- }
-
- private fun startTimer(key: Any, msg: T, duration: Duration, repeat: Boolean) {
- val timer = timers.getOrPut(key) { Timer(key) }
- timer.duration = duration
- timer.generation += 1
- timer.msg = msg
- timer.repeat = repeat
- ctx.sendSignal(ctx.self, TimerSignal(key, timer.generation), duration)
- ctx.log.debug("Start timer [{}] with generation [{}]", key, timer.generation)
- }
-
- fun interceptTimerSignal(signal: TimerSignal): T? {
- val timer = timers[signal.key]
-
- if (timer == null) {
- // Message was from canceled timer that was already enqueued
- ctx.log.debug("Received timer [{}] that has been removed, discarding", signal.key)
- return null
- } else if (signal.generation != timer.generation) {
- // Message was from an old timer that was enqueued before canceled
- ctx.log.debug("Received timer [{}] from old generation [{}], expected generation [{}], discarding",
- signal.key, signal.generation, timer.generation)
- }
-
- if (!timer.repeat) {
- timers -= timer.key
- } else {
- ctx.sendSignal(ctx.self, signal, timer.duration)
- }
-
- val msg = timer.msg
-
- if (msg is Block) {
- msg()
- return null
- }
-
- return msg
- }
-
- data class Timer<T : Any>(val key: Any) {
- var duration: Duration = 0.0
- var repeat: Boolean = false
- var generation: Int = 0
- lateinit var msg: T
- }
-
- data class TimerSignal(val key: Any, val generation: Int) : Signal
-
- data class Block(val block: () -> Unit) {
- operator fun invoke() = block()
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LocationAwareLoggerImpl.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LocationAwareLoggerImpl.kt
deleted file mode 100644
index bf50b5e8..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LocationAwareLoggerImpl.kt
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal.logging
-
-import com.atlarge.odcsim.ActorContext
-import org.slf4j.Logger
-import org.slf4j.Marker
-import org.slf4j.helpers.MessageFormatter
-import org.slf4j.spi.LocationAwareLogger
-
-/**
- * An actor-specific [Logger] implementation that is aware of the calling location.
- *
- * @param ctx The owning [ActorContext] of this logger.
- * @param delegate The [LocationAwareLogger] to delegate the messages to.
- */
-internal class LocationAwareLoggerImpl(
- ctx: ActorContext<*>,
- private val delegate: LocationAwareLogger
-) : LoggerImpl(ctx), Logger by delegate {
- /**
- * The fully qualified name of this class.
- */
- private val fqcn = LocationAwareLoggerImpl::class.java.name
-
- override fun trace(format: String?, arg: Any?) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun trace(format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun trace(format: String?, argArray: Array<Any?>) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
- delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, argArray, null)
- }
- }
-
- override fun trace(msg: String?, t: Throwable?) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, msg, null, t)
- }
- }
-
- override fun trace(marker: Marker?, msg: String?) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, msg, null, null)
- }
- }
-
- override fun trace(marker: Marker?, format: String?, arg: Any?) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun trace(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun trace(marker: Marker?, format: String?, argArray: Array<Any?>) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
- delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, argArray, null)
- }
- }
-
- override fun trace(marker: Marker?, msg: String?, t: Throwable?) {
- if (!delegate.isTraceEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, msg, null, t)
- }
- }
-
- override fun debug(msg: String?) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, null)
- }
- }
-
- override fun debug(format: String?, arg: Any?) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun debug(format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun debug(format: String?, argArray: Array<Any?>) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- val ft = MessageFormatter.arrayFormat(format, argArray)
- delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, ft.argArray, ft.throwable)
- }
- }
-
- override fun debug(msg: String?, t: Throwable?) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, t)
- }
- }
-
- override fun debug(marker: Marker?, msg: String?) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, null)
- }
- }
-
- override fun debug(marker: Marker?, format: String?, arg: Any?) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- val ft = MessageFormatter.format(format, arg)
- delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, ft.argArray, ft.throwable)
- }
- }
-
- override fun debug(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun debug(marker: Marker?, format: String?, argArray: Array<Any?>) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- val ft = MessageFormatter.arrayFormat(format, argArray)
- delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, argArray, ft.throwable)
- }
- }
-
- override fun debug(marker: Marker?, msg: String?, t: Throwable?) {
- if (!delegate.isDebugEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, t)
- }
- }
-
- override fun info(msg: String?) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, null, null)
- }
- }
-
- override fun info(format: String?, arg: Any?) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun info(format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun info(format: String?, argArray: Array<Any?>) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
- delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, argArray, null)
- }
- }
-
- override fun info(msg: String?, t: Throwable?) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, null, t)
- }
- }
-
- override fun info(marker: Marker?, msg: String?) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, msg, null, null)
- }
- }
-
- override fun info(marker: Marker?, format: String?, arg: Any?) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun info(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun info(marker: Marker?, format: String?, argArray: Array<Any?>) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
- delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, argArray, null)
- }
- }
-
- override fun info(marker: Marker?, msg: String?, t: Throwable?) {
- if (!delegate.isInfoEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, msg, null, t)
- }
- }
-
- override fun warn(msg: String?) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, null, null)
- }
- }
-
- override fun warn(format: String?, arg: Any?) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun warn(format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun warn(format: String?, argArray: Array<Any?>) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
- delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, argArray, null)
- }
- }
-
- override fun warn(msg: String?, t: Throwable?) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, null, t)
- }
- }
-
- override fun warn(marker: Marker?, msg: String?) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, msg, null, null)
- }
- }
-
- override fun warn(marker: Marker?, format: String?, arg: Any?) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun warn(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun warn(marker: Marker?, format: String?, argArray: Array<Any?>) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
- delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, argArray, null)
- }
- }
-
- override fun warn(marker: Marker?, msg: String?, t: Throwable?) {
- if (!delegate.isWarnEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, msg, null, t)
- }
- }
-
- override fun error(msg: String?) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, msg, null, null)
- }
- }
-
- override fun error(format: String?, arg: Any?) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun error(format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun error(format: String?, argArray: Array<Any?>) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
- delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, argArray, null)
- }
- }
-
- override fun error(msg: String?, t: Throwable?) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, msg, null, t)
- }
- }
-
- override fun error(marker: Marker?, msg: String?) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, msg, null, null)
- }
- }
-
- override fun error(marker: Marker?, format: String?, arg: Any?) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg).message
- delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg), null)
- }
- }
-
- override fun error(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
- delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg1, arg2), null)
- }
- }
-
- override fun error(marker: Marker?, format: String?, argArray: Array<Any?>) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
- delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, argArray, null)
- }
- }
-
- override fun error(marker: Marker?, msg: String?, t: Throwable?) {
- if (!delegate.isErrorEnabled) {
- return
- }
-
- withMdc {
- delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, msg, null, t)
- }
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LocationIgnorantLoggerImpl.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LocationIgnorantLoggerImpl.kt
deleted file mode 100644
index 999e30e6..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LocationIgnorantLoggerImpl.kt
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal.logging
-
-import com.atlarge.odcsim.ActorContext
-import org.slf4j.Logger
-import org.slf4j.Marker
-
-/**
- * A [Logger] implementation that is not aware of the calling location.
- *
- * @param ctx The owning [ActorContext] of this logger.
- * @param delegate The [Logger] to delegate the messages to.
- */
-internal class LocationIgnorantLoggerImpl(
- ctx: ActorContext<*>,
- private val delegate: Logger
-) : LoggerImpl(ctx), Logger by delegate {
- override fun warn(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(marker, format, arg1, arg2) }
- }
-
- override fun warn(format: String?, arg1: Any?, arg2: Any?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(format, arg1, arg2) }
- }
-
- override fun warn(msg: String?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(msg) }
- }
-
- override fun warn(marker: Marker?, format: String?, arg: Any?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(marker, format, arg) }
- }
-
- override fun warn(marker: Marker?, format: String?, vararg arguments: Any?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(marker, format, arguments) }
- }
-
- override fun warn(format: String?, arg: Any?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(format, arg) }
- }
-
- override fun warn(marker: Marker?, msg: String?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(marker, msg) }
- }
-
- override fun warn(msg: String?, t: Throwable?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(msg, t) }
- }
-
- override fun warn(format: String?, vararg arguments: Any?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(format, *arguments) }
- }
-
- override fun warn(marker: Marker?, msg: String?, t: Throwable?) {
- if (!isWarnEnabled) {
- return
- }
-
- withMdc { delegate.warn(marker, msg, t) }
- }
-
- override fun info(marker: Marker?, format: String?, vararg arguments: Any?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(marker, format, *arguments) }
- }
-
- override fun info(format: String?, arg: Any?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(format, arg) }
- }
-
- override fun info(marker: Marker?, msg: String?, t: Throwable?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(marker, msg, t) }
- }
-
- override fun info(msg: String?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(msg) }
- }
-
- override fun info(format: String?, vararg arguments: Any?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(format, *arguments) }
- }
-
- override fun info(format: String?, arg1: Any?, arg2: Any?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(format, arg1, arg2) }
- }
-
- override fun info(marker: Marker?, msg: String?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(marker, msg) }
- }
-
- override fun info(marker: Marker?, format: String?, arg: Any?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(marker, format, arg) }
- }
-
- override fun info(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(marker, format, arg1, arg2) }
- }
-
- override fun info(msg: String?, t: Throwable?) {
- if (!isInfoEnabled) {
- return
- }
-
- withMdc { delegate.info(msg, t) }
- }
-
- override fun error(msg: String?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(msg) }
- }
-
- override fun error(marker: Marker?, msg: String?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(marker, msg) }
- }
-
- override fun error(format: String?, vararg arguments: Any?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(format, *arguments) }
- }
-
- override fun error(format: String?, arg: Any?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(format, arg) }
- }
-
- override fun error(msg: String?, t: Throwable?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(msg, t) }
- }
-
- override fun error(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(marker, format, arg1, arg2) }
- }
-
- override fun error(marker: Marker?, format: String?, vararg arguments: Any?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(marker, format, *arguments) }
- }
-
- override fun error(marker: Marker?, msg: String?, t: Throwable?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(marker, msg, t) }
- }
-
- override fun error(format: String?, arg1: Any?, arg2: Any?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(format, arg1, arg2) }
- }
-
- override fun error(marker: Marker?, format: String?, arg: Any?) {
- if (!isErrorEnabled) {
- return
- }
-
- withMdc { delegate.error(marker, format, arg) }
- }
-
- override fun debug(format: String?, vararg arguments: Any?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(format, *arguments) }
- }
-
- override fun debug(format: String?, arg1: Any?, arg2: Any?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(format, arg1, arg2) }
- }
-
- override fun debug(msg: String?, t: Throwable?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(msg, t) }
- }
-
- override fun debug(format: String?, arg: Any?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(format, arg) }
- }
-
- override fun debug(marker: Marker?, msg: String?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(marker, msg) }
- }
-
- override fun debug(msg: String?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(msg) }
- }
-
- override fun debug(marker: Marker?, msg: String?, t: Throwable?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(marker, msg, t) }
- }
-
- override fun debug(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(marker, format, arg1, arg2) }
- }
-
- override fun debug(marker: Marker?, format: String?, arg: Any?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(marker, format, arg) }
- }
-
- override fun debug(marker: Marker?, format: String?, vararg arguments: Any?) {
- if (!isDebugEnabled) {
- return
- }
-
- withMdc { delegate.debug(marker, format, *arguments) }
- }
-
- override fun trace(format: String?, arg: Any?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(format, arg) }
- }
-
- override fun trace(marker: Marker?, msg: String?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(marker, msg) }
- }
-
- override fun trace(msg: String?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(msg) }
- }
-
- override fun trace(msg: String?, t: Throwable?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(msg, t) }
- }
-
- override fun trace(format: String?, arg1: Any?, arg2: Any?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(format, arg1, arg2) }
- }
-
- override fun trace(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(marker, format, arg1, arg2) }
- }
-
- override fun trace(marker: Marker?, format: String?, arg: Any?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(marker, format, arg) }
- }
-
- override fun trace(marker: Marker?, format: String?, vararg argArray: Any?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(marker, format, *argArray) }
- }
-
- override fun trace(marker: Marker?, msg: String?, t: Throwable?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(marker, msg, t) }
- }
-
- override fun trace(format: String?, vararg arguments: Any?) {
- if (!isTraceEnabled) {
- return
- }
-
- withMdc { delegate.trace(format, *arguments) }
- }
-}
diff --git a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LoggerImpl.kt b/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LoggerImpl.kt
deleted file mode 100644
index f971f08d..00000000
--- a/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/internal/logging/LoggerImpl.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 atlarge-research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package com.atlarge.odcsim.internal.logging
-
-import com.atlarge.odcsim.ActorContext
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.slf4j.MDC
-import org.slf4j.spi.LocationAwareLogger
-
-/**
- * An actor-specific [Logger] implementation.
- *
- * @param ctx The owning [ActorContext] of this logger.
- */
-abstract class LoggerImpl internal constructor(protected val ctx: ActorContext<*>) : Logger {
- /**
- * Configure [MDC] with actor-specific information.
- */
- protected inline fun withMdc(block: () -> Unit) {
- MDC.put(MDC_ACTOR_SYSTEM, ctx.system.name)
- MDC.put(MDC_ACTOR_TIME, String.format("%.2f", ctx.time))
- MDC.put(MDC_ACTOR_REF, ctx.self.path.toString())
- try {
- block()
- } finally {
- MDC.remove(MDC_ACTOR_SYSTEM)
- MDC.remove(MDC_ACTOR_TIME)
- MDC.remove(MDC_ACTOR_REF)
- }
- }
-
- /**
- * Mapped Diagnostic Context (MDC) attribute names.
- */
- companion object {
- val MDC_ACTOR_SYSTEM = "actor.system"
- val MDC_ACTOR_TIME = "actor.time"
- val MDC_ACTOR_REF = "actor.ref"
-
- /**
- * Create a [Logger] for the specified [ActorContext].
- *
- * @param ctx The actor context to create the logger for.
- */
- operator fun invoke(ctx: ActorContext<*>): Logger {
- val logger = LoggerFactory.getLogger(ctx.javaClass)
- return if (logger is LocationAwareLogger) {
- LocationAwareLoggerImpl(ctx, logger)
- } else {
- LocationIgnorantLoggerImpl(ctx, logger)
- }
- }
- }
-}