9e1b7498e1343de6cf0369fe8a2741bc39a1e429
[ccsdk/cds.git] / ms / controllerblueprints / modules / blueprint-core / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / core / data / BluePrintGraph.kt
1 /*
2  *  Copyright © 2019 IBM.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16
17 package org.onap.ccsdk.cds.controllerblueprints.core.data
18
19 enum class EdgeLabel(val id: String) {
20     SUCCESS("success"),
21     FAILURE("failure"),
22     DEFAULT("*")
23 }
24
25 enum class EdgeStatus(val id: String) {
26     NOT_STARTED("not_started"),
27     EXECUTED("executed"),
28     SKIPPED("skipped")
29 }
30
31 enum class NodeStatus(val id: String) {
32     NOT_STARTED("not_started"),
33     READY("ready"),
34     EXECUTING("executing"),
35     EXECUTED("executed"),
36     SKIPPED("skipped")
37 }
38
39 class Graph {
40     val nodes: MutableMap<String, Node> = hashMapOf()
41     val edges: MutableSet<Edge> = mutableSetOf()
42
43     fun addNode(value: String): Node {
44         val node = Node(value)
45         nodes[value] = node
46         return node
47     }
48
49     fun addEdge(source: String, destination: String, label: EdgeLabel) {
50         if (!nodes.containsKey(source)) {
51             addNode(source)
52         }
53         if (!nodes.containsKey(destination)) {
54             addNode(destination)
55         }
56         val edge = Edge(nodes[source]!!, nodes[destination]!!, label)
57         if (!edges.contains(edge)) {
58             edges.add(edge)
59             nodes[source]!!.edges.add(edge)
60         }
61     }
62
63     override fun toString(): String {
64         val standaloneNodes = nodes.values.filter { node -> edges.all { it.source != node && it.target != node } }
65         val s = (edges.map { it.toString() } + standaloneNodes.map { it.toString() }).joinToString()
66         return "[$s]"
67     }
68
69     fun print(): String {
70         val buffer = StringBuffer("Nodes :")
71         nodes.values.forEach {
72             buffer.append("\n\t$it")
73         }
74         buffer.append("\nEdges :")
75         edges.forEach {
76             buffer.append("\n\t$it")
77         }
78         return buffer.toString()
79     }
80
81     override fun equals(other: Any?): Boolean {
82         if (this === other) return true
83         if (other?.javaClass != javaClass) return false
84         other as Graph
85         return nodes == other.nodes && edges == other.edges
86     }
87
88     override fun hashCode() = 31 * nodes.hashCode() + edges.hashCode()
89
90     fun equivalentTo(other: Graph): Boolean {
91         return nodes == other.nodes && edges.all { edge -> other.edges.any { it.equivalentTo(edge) } }
92     }
93
94     data class Node(val id: String, var status: NodeStatus = NodeStatus.NOT_STARTED) {
95         val edges: MutableList<Edge> = ArrayList()
96
97         fun neighbors(): List<Node> = edges.map { edge -> edge.target(this) }
98
99         fun neighbors(label: EdgeLabel): List<Node> = edges.filter { it.label == label }
100                 .map { edge -> edge.target(this) }
101
102         fun labelEdges(label: EdgeLabel): List<Edge> = edges.filter { it.label == label }
103
104         override fun toString() = "$id, Status($status)"
105     }
106
107     data class Edge(
108             val source: Node,
109             val target: Node,
110             val label: EdgeLabel,
111             var status: EdgeStatus = EdgeStatus.NOT_STARTED) {
112
113         fun target(node: Node): Node = target
114
115         fun equivalentTo(other: Edge) =
116                 (source == other.source && target == other.target)
117                         || (source == other.target && target == other.source)
118
119         override fun toString() =
120                 "${source.id}>${target.id}/$label($status)"
121     }
122
123     data class TermForm(val nodes: Collection<String>, val edges: List<Term>) {
124
125         data class Term(val source: String, val target: String, val label: EdgeLabel) {
126             override fun toString() = "Term($source, $target, $label)"
127         }
128     }
129
130     data class AdjacencyList<String, out EdgeLabel>(val entries: List<Entry<String, EdgeLabel>>) {
131         constructor(vararg entries: Entry<String, EdgeLabel>) : this(entries.asList())
132
133         override fun toString() = "AdjacencyList(${entries.joinToString()})"
134
135         data class Entry<out String, out EdgeLabel>(val node: String, val links: List<Link<String, EdgeLabel>> = emptyList<Nothing>()) {
136             constructor(node: String, vararg links: Link<String, EdgeLabel>) : this(node, links.asList())
137
138             override fun toString() = "Entry($node, links[${links.joinToString()}])"
139         }
140
141         data class Link<out String, out EdgeLabel>(val node: String, val label: EdgeLabel) {
142             override fun toString() = if (label == null) "$node" else "$node/$label"
143         }
144     }
145
146     companion object {
147
148         fun labeledDirectedTerms(termForm: TermForm): Graph =
149                 createFromTerms(termForm) { graph, n1, n2, value -> graph.addEdge(n1, n2, value) }
150
151         fun labeledDirectedAdjacent(adjacencyList: AdjacencyList<String, EdgeLabel>): Graph =
152                 fromAdjacencyList(adjacencyList) { graph, n1, n2, value ->
153                     graph.addEdge(n1, n2, value)
154                 }
155
156         private fun createFromTerms(termForm: TermForm,
157                                     addFunction: (Graph, String, String, EdgeLabel) -> Unit): Graph {
158             val graph = Graph()
159             termForm.nodes.forEach { graph.addNode(it) }
160             termForm.edges.forEach { addFunction(graph, it.source, it.target, it.label) }
161             return graph
162         }
163
164         private fun fromAdjacencyList(adjacencyList: AdjacencyList<String, EdgeLabel>,
165                                       addFunction: (Graph, String, String, EdgeLabel) -> Unit): Graph {
166             val graph = Graph()
167             adjacencyList.entries.forEach { graph.addNode(it.node) }
168             adjacencyList.entries.forEach { (node, links) ->
169                 links.forEach { addFunction(graph, node, it.node, it.label) }
170             }
171             return graph
172         }
173     }
174 }