diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2018-02-23 12:17:48 +0100 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2018-02-23 12:17:48 +0100 |
| commit | f691a72b12a43fa15c1617966450c55206664797 (patch) | |
| tree | e76afd3b1d5673a29d71eedb9d373396976d84bd /opendc-stdlib/src/main/kotlin/com | |
| parent | 8666a78b86a40c1d8dab28dd18e841318c01f97f (diff) | |
| parent | 86dc826db4cd91b5a6875d9ecdd64c9238d7b95c (diff) | |
refactor(#18): Redesign core simulation API
This change contains the redesign of the core simulation API and
provides a cleaner interface for developing simulation models for the
users.
Closes #18
Diffstat (limited to 'opendc-stdlib/src/main/kotlin/com')
12 files changed, 770 insertions, 0 deletions
diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt new file mode 100644 index 00000000..db117917 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt @@ -0,0 +1,260 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity +import java.util.concurrent.atomic.AtomicInteger +import com.atlarge.opendc.model.topology.Edge as BaseEdge + +/** + * This module provides a [Topology] implementation backed internally by an adjacency list. + * + * This implementation is best suited for sparse graphs, where an adjacency matrix would take up too much space with + * empty cells. + * + * *Note that this implementation is not synchronized.* + */ +object AdjacencyList { + /** + * Return a [TopologyBuilder] that constructs the topology represents as an adjacency list. + * + * @return A [TopologyBuilder] instance. + */ + fun builder(): TopologyBuilder = AdjacencyListTopologyBuilder() +} + +/** + * A builder for [Topology] instances, which is backed by an adjacency list. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +internal class AdjacencyListTopologyBuilder : TopologyBuilder { + /** + * Build a [Topology] instance from the current state of this builder. + * + * @return The graph built from this builder. + */ + override fun create(): MutableTopology = AdjacencyListTopology() +} + +/** + * A [Topology] whose graph is represented as adjacency list. + */ +internal class AdjacencyListTopology : MutableTopology { + /** + * The identifier for the next node in the graph. + */ + private var nextId: AtomicInteger = AtomicInteger(0) + + /** + * A mapping of nodes to their internal representation with the edges of the nodes. + */ + private var nodes: MutableMap<Entity<*, Topology>, Node> = HashMap() + + // Topology + + /** + * The listeners of this topology. + */ + override val listeners: MutableSet<TopologyListener> = HashSet() + + /** + * A unique identifier of this node within the topology. + */ + override val Entity<*, Topology>.id: Int + get() = nodes[this]!!.id + + /** + * The set of ingoing edges of this node. + */ + override val Entity<*, Topology>.ingoingEdges: MutableSet<BaseEdge<*>> + get() = nodes[this]!!.ingoingEdges + + /** + * The set of outgoing edges of this node. + */ + override val Entity<*, Topology>.outgoingEdges: MutableSet<BaseEdge<*>> + get() = nodes[this]!!.outgoingEdges + + // MutableTopology + + /** + * Create a directed edge between two [Node]s in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param label The label of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + override fun <T> connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String?): BaseEdge<T> { + if (!contains(from) || !contains(to)) + throw IllegalArgumentException("One of the entities is not part of the topology") + val edge = Edge(label, tag, from, to) + from.outgoingEdges.add(edge) + to.ingoingEdges.add(edge) + listeners.forEach { it.run { this@AdjacencyListTopology.onEdgeAdded(edge) } } + return edge + } + + // Cloneable + + /** + * Create a copy of the graph. + * + * @return A new [Topology] instance with a copy of the graph. + */ + override fun clone(): Topology { + val copy = AdjacencyListTopology() + copy.nextId = AtomicInteger(nextId.get()) + copy.nodes = HashMap(nodes) + return copy + } + + // Set + + /** + * Returns the size of the collection. + */ + override val size: Int = nodes.size + + /** + * Checks if the specified element is contained in this collection. + */ + override fun contains(element: Entity<*, Topology>): Boolean = nodes.contains(element) + + /** + * Checks if all elements in the specified collection are contained in this collection. + */ + override fun containsAll(elements: Collection<Entity<*, Topology>>): Boolean = + elements.all { nodes.containsKey(it) } + + /** + * Returns `true` if the collection is empty (contains no elements), `false` otherwise. + */ + override fun isEmpty(): Boolean = nodes.isEmpty() + + // MutableSet + + /** + * Add a node to the graph. + * + * @param element The element to add to this graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun add(element: Entity<*, Topology>): Boolean { + if (nodes.putIfAbsent(element, Node(nextId.getAndIncrement())) == null) { + listeners.forEach { it.run { this@AdjacencyListTopology.onNodeAdded(element) } } + return true + } + return false + } + + /** + * Add all nodes in the specified collection to the graph. + * + * @param elements The nodes to add to this graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun addAll(elements: Collection<Entity<*, Topology>>): Boolean = elements.any { add(it) } + + /** + * Remove all nodes and their respective edges from the graph. + */ + override fun clear() = nodes.clear() + + /** + * Remove the given node and its edges from the graph. + * + * @param element The element to remove from the graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun remove(element: Entity<*, Topology>): Boolean { + nodes[element]?.ingoingEdges?.forEach { + it.from.outgoingEdges.remove(it) + } + nodes[element]?.outgoingEdges?.forEach { + it.to.ingoingEdges.remove(it) + } + if (nodes.keys.remove(element)) { + listeners.forEach { it.run { this@AdjacencyListTopology.onNodeRemoved(element) } } + return true + } + return false + } + + + /** + * Remove all nodes in the given collection from the graph. + * + * @param elements The elements to remove from the graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun removeAll(elements: Collection<Entity<*, Topology>>): Boolean = elements.any(this::remove) + + /** + * Remove all nodes in the graph, except those in the specified collection. + * + * Take note that this method currently only guarantees a maximum runtime complexity of O(n^2). + * + * @param elements The elements to retain in the graph. + */ + override fun retainAll(elements: Collection<Entity<*, Topology>>): Boolean { + val iterator = nodes.keys.iterator() + var changed = false + while (iterator.hasNext()) { + val entity = iterator.next() + + if (entity !in elements) { + iterator.remove() + changed = true + } + } + return changed + } + + /** + * Return a mutable iterator over the nodes of the graph. + * + * @return A [MutableIterator] over the nodes of the graph. + */ + override fun iterator(): MutableIterator<Entity<*, Topology>> = nodes.keys.iterator() + + /** + * The internal representation of a node within the graph. + */ + internal data class Node(val id: Int) { + val ingoingEdges: MutableSet<BaseEdge<*>> = HashSet() + val outgoingEdges: MutableSet<BaseEdge<*>> = HashSet() + } + + /** + * The internal representation of an edge within the graph. + */ + internal class Edge<out T>(override val label: T, + override val tag: String?, + override val from: Entity<*, Topology>, + override val to: Entity<*, Topology>) : BaseEdge<T> +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt new file mode 100644 index 00000000..e0b54a28 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt @@ -0,0 +1,23 @@ +package com.atlarge.opendc.model.topology + +import com.atlarge.opendc.simulator.Bootstrap +import com.atlarge.opendc.simulator.Entity + +/** + * Create a [Bootstrap] procedure for the given [Topology]. + * + * @return A apply procedure for the topology. + */ +fun <T : Topology> T.bootstrap(): Bootstrap<T> = Bootstrap.create { ctx -> + forEach { ctx.register(it) } + listeners += object : TopologyListener { + override fun Topology.onNodeAdded(node: Entity<*, Topology>) { + ctx.register(node) + } + + override fun Topology.onNodeRemoved(node: Entity<*, Topology>) { + ctx.deregister(node) + } + } + this +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Component.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Component.kt new file mode 100644 index 00000000..5e8611a0 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Component.kt @@ -0,0 +1,33 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +/** + * A component within a [Topology], which is either a node or an [Edge] representing the relationship between + * entities within a logical topology of a cloud network. + ** + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface Component diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt new file mode 100644 index 00000000..1963a056 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt @@ -0,0 +1,61 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity + +/** + * An edge that represents a directed relationship between exactly two nodes in a logical topology of a cloud network. + * + * @param T The relationship type the edge represents within a logical topology. + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface Edge<out T> : Component { + /** + * The label of this edge. + */ + val label: T + + /** + * A tag to uniquely identify the relationship this edge represents. + */ + val tag: String? + + /** + * The source of the edge. + * + * This property is not guaranteed to have a runtime complexity of <code>O(1)</code>, but must be at least + * <code>O(n)</code>, with respect to the size of the topology. + */ + val from: Entity<*, Topology> + + /** + * The destination of the edge. + * + * This property is not guaranteed to have a runtime complexity of <code>O(1)</code>, but must be at least + * <code>O(n)</code>, with respect to the size of the topology. + */ + val to: Entity<*, Topology> +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt new file mode 100644 index 00000000..7cf80702 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt @@ -0,0 +1,65 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity + +/** + * A subinterface of [Topology] which adds mutation methods. When mutation is not required, users + * should prefer the [Topology] interface. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface MutableTopology : Topology, MutableSet<Entity<*, Topology>> { + /** + * Create a directed, labeled edge between two nodes in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param label The label of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + fun <T> connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String? = null): Edge<T> + + /** + * Create a directed, unlabeled edge between two nodes in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, tag: String? = null): Edge<Unit> = + connect(from, to, Unit, tag) + + /** + * Create a directed, unlabeled edge between two nodes in the topology. + * + * @param dest The destination of the edge. + * @return The edge that has been created. + */ + infix fun Entity<*, Topology>.to(dest: Entity<*, Topology>): Edge<Unit> = connect(this, dest) +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt new file mode 100644 index 00000000..e277bc9f --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt @@ -0,0 +1,50 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity + +/** + * A graph data structure which represents the logical topology of a cloud network consisting of one or more + * datacenters. + * + * A topology is [Iterable] and allows implementation-dependent iteration of the nodes in the topology. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface Topology : TopologyContext, Cloneable, Set<Entity<*, Topology>> { + /** + * The listeners of this topology. + */ + val listeners: MutableSet<TopologyListener> + + /** + * Create a copy of the topology. + * + * @return A new [Topology] with a copy of the graph. + */ + public override fun clone(): Topology +} + diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt new file mode 100644 index 00000000..8bdc37c0 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt @@ -0,0 +1,40 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +/** + * A builder for [Topology] instances. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface TopologyBuilder : TopologyFactory { + /** + * Construct a [Topology] from the given block and return it. + * + * @param block The block to construct the topology. + * @return The topology that has been built. + */ + fun construct(block: MutableTopology.() -> Unit): MutableTopology = create().apply(block) +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt new file mode 100644 index 00000000..9d78b5eb --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt @@ -0,0 +1,50 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity + +/** + * A [TopologyContext] represents the context for entities in a specific topology, providing access to the identifier + * and ingoing and outgoing edges of the [Entity] within a [Topology]. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface TopologyContext { + /** + * A unique identifier of an [Entity] within the topology. + */ + val Entity<*, Topology>.id: Int + + /** + * The set of ingoing edges of an [Entity]. + */ + val Entity<*, Topology>.ingoingEdges: Set<Edge<*>> + + /** + * The set of outgoing edges of an [Entity]. + */ + val Entity<*, Topology>.outgoingEdges: Set<Edge<*>> +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt new file mode 100644 index 00000000..ab2deeb7 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt @@ -0,0 +1,40 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +/** + * An interface for producing [Topology] instances. Implementors of this interface provide a way of generating a + * topology based on the state of the factory. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface TopologyFactory { + /** + * Create a [MutableTopology] instance. + * + * @return A mutable topology. + */ + fun create(): MutableTopology +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt new file mode 100644 index 00000000..0b4d43f7 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt @@ -0,0 +1,63 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology; + +import com.atlarge.opendc.simulator.Entity + +/** + * A listener interface for [Topology] instances. The methods of this interface are invoked on + * mutation of the topology the listener is listening to. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface TopologyListener { + /** + * This method is invoked when an [Entity] is added to the [Topology]. + * + * @param node The entity that has been added to the [Topology]. + */ + fun Topology.onNodeAdded(node: Entity<*, Topology>) {} + + /** + * This method is invoked when an [Entity] is removed from the [Topology]. + * + * @param node The entity that has been removed from the [Topology]. + */ + fun Topology.onNodeRemoved(node: Entity<*, Topology>) {} + + /** + * This method is invoked when an [Edge] is added to the [Topology]. + * + * @param edge The edge that has been added to the [Topology]. + */ + fun Topology.onEdgeAdded(edge: Edge<*>) {} + + /** + * This method is invoked when an [Edge] is removed from the [Topology]. + * + * @param edge The entity that has been removed from the [Topology]. + */ + fun Topology.onEdgeRemoved(edge: Edge<*>) {} +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Traversable.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Traversable.kt new file mode 100644 index 00000000..23720c46 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Traversable.kt @@ -0,0 +1,41 @@ +/* + * MIT License + * + * Copyright (c) 2017 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.opendc.model.topology + +/** + * Filter a [Set] of [Edge]s based on the tag of the edges and return the origin nodes casted to type `T`. + * + * @param tag The tag of the edges to get. + * @return An [Iterable] of the specified type `T` with the given tag. + */ +inline fun <reified T> Set<Edge<*>>.origins(tag: String) = filter { it.tag == tag }.map { it.from as T } + +/** + * Filter a [Set] of [Edge]s based on the tag of the edges and return the destination nodes casted to type `T`. + * + * @param tag The tag of the edges to get. + * @return An [Iterable] of the specified type `T` with the given tag. + */ +inline fun <reified T> Set<Edge<*>>.destinations(tag: String) = filter { it.tag == tag }.map { it.to as T } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt new file mode 100644 index 00000000..0f6392ed --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt @@ -0,0 +1,44 @@ +package com.atlarge.opendc.simulator + +import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn + +/** + * Try to find the [Context] instance associated with the [Process] in the call chain which has (indirectly) invoked the + * caller of this method. + * + * Note however that this method does not guarantee type-safety as this method allows the user to cast to a context + * with different generic type arguments. + * + * @return The context that has been found or `null` if this method is not called in a simulation context. + */ +suspend fun <S, M> contextOrNull(): Context<S, M>? = suspendCoroutineOrReturn { it.context[Context] } + +/** + * Find the [Context] instance associated with the [Process] in the call chain which has (indirectly) invoked the + * caller of this method. + * + * Note however that this method does not guarantee type-safety as this method allows the user to cast to a context + * with different generic type arguments. + * + * @throws IllegalStateException if the context cannot be found. + * @return The context that has been found. + */ +suspend fun <S, M> context(): Context<S, M> = + contextOrNull() ?: throw IllegalStateException("The suspending call does not have an associated process context") + +/** + * Try to find the untyped [Context] instance associated with the [Process] in the call chain which has (indirectly) + * invoked the caller of this method. + * + * @return The untyped context that has been found or `null` if this method is not called in a simulation context. + */ +suspend fun untypedContextOrNull(): Context<*, *>? = contextOrNull<Any?, Any?>() + +/** + * Find the [Context] instance associated with the [Process] in the call chain which has (indirectly) invoked the + * caller of this method. + * + * @throws IllegalStateException if the context cannot be found. + * @return The untyped context that has been found. + */ +suspend fun untypedContext(): Context<*, *> = context<Any?, Any?>() |
