4578aca7d8ede23250211648b2d8425804e9e81d
[ccsdk/apps.git] /
1 /*
2  *  Copyright © 2017-2018 AT&T Intellectual Property.
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.apps.controllerblueprints.resource.dict.service
18
19 import org.apache.commons.collections.CollectionUtils
20 import org.apache.commons.lang3.StringUtils
21 import org.apache.commons.lang3.text.StrBuilder
22 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException
23 import org.onap.ccsdk.apps.controllerblueprints.core.utils.TopologicalSortingUtils
24 import org.onap.ccsdk.apps.controllerblueprints.resource.dict.ResourceAssignment
25 import org.slf4j.LoggerFactory
26 import java.io.Serializable
27
28 /**
29  * ResourceAssignmentValidationService.
30  *
31  * @author Brinda Santh
32  */
33 interface ResourceAssignmentValidationService : Serializable {
34
35     @Throws(BluePrintException::class)
36     fun validate(resourceAssignments: List<ResourceAssignment>): Boolean
37 }
38
39 /**
40  * ResourceAssignmentValidationDefaultService.
41  *
42  * @author Brinda Santh
43  */
44 open class ResourceAssignmentValidationDefaultService : ResourceAssignmentValidationService {
45     private val log = LoggerFactory.getLogger(ResourceAssignmentValidationDefaultService::class.java)
46
47     open var resourceAssignmentMap: Map<String, ResourceAssignment> = hashMapOf()
48     open val validationMessage = StrBuilder()
49
50     override fun validate(resourceAssignments: List<ResourceAssignment>): Boolean {
51         try {
52             validateSources(resourceAssignments)
53             validateTemplateNDictionaryKeys(resourceAssignments)
54             validateCyclicDependency(resourceAssignments)
55             if (StringUtils.isNotBlank(validationMessage)) {
56                 throw BluePrintException("Resource Assignment Validation Failure")
57             }
58         } catch (e: Exception) {
59             throw BluePrintException("Resource Assignment Validation :" + validationMessage.toString(), e)
60         }
61         return true
62     }
63
64     open fun validateSources(resourceAssignments: List<ResourceAssignment>) {
65         log.info("validating resource assignment sources")
66     }
67
68     open fun validateTemplateNDictionaryKeys(resourceAssignments: List<ResourceAssignment>) {
69
70         resourceAssignmentMap = resourceAssignments.map { it.name to it }.toMap()
71
72         val duplicateKeyNames = resourceAssignments.groupBy { it.name }
73                 .filter { it.value.size > 1 }
74                 .map { it.key }
75
76         if (duplicateKeyNames.isNotEmpty()) {
77             validationMessage.appendln(String.format("Duplicate Assignment Template Keys (%s) is Present", duplicateKeyNames))
78         }
79
80         val duplicateDictionaryKeyNames = resourceAssignments.groupBy { it.dictionaryName }
81                 .filter { it.value.size > 1 }
82                 .map { it.key }
83         if (duplicateDictionaryKeyNames.isNotEmpty()) {
84             validationMessage.appendln(String.format("Duplicate Assignment Dictionary Keys (%s) is Present", duplicateDictionaryKeyNames))
85         }
86
87         val dependenciesNames = resourceAssignments.mapNotNull { it.dependencies }.flatten()
88
89         log.info("Resource assignment definitions : {}", resourceAssignmentMap.keys)
90         log.info("Resource assignment Dictionary dependencies : {}", dependenciesNames)
91
92         val notPresentDictionaries = dependenciesNames.filter { !resourceAssignmentMap.containsKey(it) }.distinct()
93         if (notPresentDictionaries.isNotEmpty()) {
94             validationMessage.appendln(String.format("No assignments for Dictionary Keys (%s)", notPresentDictionaries))
95         }
96
97         if (StringUtils.isNotBlank(validationMessage)) {
98             throw BluePrintException("Resource Assignment Validation Failure")
99         }
100     }
101
102     open fun validateCyclicDependency(resourceAssignments: List<ResourceAssignment>) {
103         val startResourceAssignment = ResourceAssignment()
104         startResourceAssignment.name = "*"
105
106         val topologySorting = TopologicalSortingUtils<ResourceAssignment>()
107
108         resourceAssignmentMap.map { it.value }.map { resourceAssignment ->
109             if (CollectionUtils.isNotEmpty(resourceAssignment.dependencies)) {
110                 resourceAssignment.dependencies!!.map {
111                     log.info("Topological Graph link from {} to {}", it, resourceAssignment.name)
112                     topologySorting.add(resourceAssignmentMap[it]!!, resourceAssignment)
113                 }
114             } else {
115                 topologySorting.add(startResourceAssignment, resourceAssignment)
116             }
117         }
118
119         if (!topologySorting.isDag) {
120             val graph = getTopologicalGraph(topologySorting)
121             validationMessage.appendln("Cyclic Dependency :$graph")
122         }
123     }
124
125     open fun getTopologicalGraph(topologySorting: TopologicalSortingUtils<ResourceAssignment>): String {
126         val s = StringBuilder()
127         val neighbors = topologySorting.getNeighbors()
128
129         neighbors.forEach { v, vs ->
130             if (v.name == "*") {
131                 s.append("\n    * -> [")
132                 for (resourceAssignment in vs) {
133                     s.append("(" + resourceAssignment.dictionaryName + ":" + resourceAssignment.name
134                             + "),")
135                 }
136                 s.append("]")
137             } else {
138                 s.append("\n    (" + v.dictionaryName + ":" + v.name + ") -> [")
139                 for (resourceAssignment in vs) {
140                     s.append("(" + resourceAssignment.dictionaryName + ":" + resourceAssignment.name
141                             + "),")
142                 }
143                 s.append("]")
144             }
145         }
146         return s.toString()
147     }
148
149
150 }