94d6251cc99135a4e65e6c6a0b696d0e426a6543
[ccsdk/cds.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.core.validation
18
19 import com.att.eelf.configuration.EELFLogger
20 import com.att.eelf.configuration.EELFManager
21 import com.fasterxml.jackson.databind.JsonNode
22 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException
23 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintTypes
24 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintValidationError
25 import org.onap.ccsdk.apps.controllerblueprints.core.data.*
26 import org.onap.ccsdk.apps.controllerblueprints.core.format
27 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintNodeTemplateValidator
28 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintTypeValidatorService
29 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintContext
30 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintExpressionService
31 import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils
32
33
34 open class BluePrintNodeTemplateValidatorImpl(private val bluePrintTypeValidatorService: BluePrintTypeValidatorService) : BluePrintNodeTemplateValidator {
35
36     private val log: EELFLogger = EELFManager.getInstance().getLogger(BluePrintNodeTemplateValidatorImpl::class.toString())
37
38     var bluePrintContext: BluePrintContext? = null
39     var error: BluePrintValidationError? = null
40     var paths: MutableList<String> = arrayListOf()
41
42     override fun validate(bluePrintContext: BluePrintContext, error: BluePrintValidationError, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
43         log.trace("Validating NodeTemplate($nodeTemplateName)")
44         this.bluePrintContext = bluePrintContext
45         this.error = error
46
47         paths.add(nodeTemplateName)
48
49         val type: String = nodeTemplate.type
50
51         val nodeType: NodeType = bluePrintContext.serviceTemplate.nodeTypes?.get(type)
52                 ?: throw BluePrintException("Failed to get NodeType($type) definition for NodeTemplate($nodeTemplateName)")
53
54         nodeTemplate.properties?.let { validatePropertyAssignments(nodeType.properties!!, nodeTemplate.properties!!) }
55         nodeTemplate.capabilities?.let { validateCapabilityAssignments(nodeType, nodeTemplateName, nodeTemplate) }
56         nodeTemplate.requirements?.let { validateRequirementAssignments(nodeType, nodeTemplateName, nodeTemplate) }
57         nodeTemplate.interfaces?.let { validateInterfaceAssignments(nodeType, nodeTemplateName, nodeTemplate) }
58         nodeTemplate.artifacts?.let { validateArtifactDefinitions(nodeTemplate.artifacts!!) }
59
60         paths.removeAt(paths.lastIndex)
61     }
62
63     @Throws(BluePrintException::class)
64     open fun validateArtifactDefinitions(artifacts: MutableMap<String, ArtifactDefinition>) {
65         paths.add("artifacts")
66         artifacts.forEach { artifactDefinitionName, artifactDefinition ->
67             paths.add(artifactDefinitionName)
68             val type: String = artifactDefinition.type
69                     ?: throw BluePrintException("type is missing for ArtifactDefinition$artifactDefinitionName)")
70             // Check Artifact Type
71             checkValidArtifactType(artifactDefinitionName, type)
72
73             val file: String = artifactDefinition.file
74                     ?: throw BluePrintException("file is missing for ArtifactDefinition($artifactDefinitionName)")
75
76             paths.removeAt(paths.lastIndex)
77         }
78         paths.removeAt(paths.lastIndex)
79     }
80
81
82     @Throws(BluePrintException::class)
83     open fun validatePropertyAssignments(nodeTypeProperties: MutableMap<String, PropertyDefinition>,
84                                          properties: MutableMap<String, JsonNode>) {
85         properties.forEach { propertyName, propertyAssignment ->
86             val propertyDefinition: PropertyDefinition = nodeTypeProperties[propertyName]
87                     ?: throw BluePrintException("failed to get definition for the property ($propertyName)")
88
89             validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
90
91         }
92     }
93
94     @Throws(BluePrintException::class)
95     open fun validatePropertyAssignment(propertyName: String, propertyDefinition: PropertyDefinition,
96                                         propertyAssignment: JsonNode) {
97         // Check and Validate if Expression Node
98         val expressionData = BluePrintExpressionService.getExpressionData(propertyAssignment)
99         if (!expressionData.isExpression) {
100             checkPropertyValue(propertyName, propertyDefinition, propertyAssignment)
101         }
102     }
103
104     @Throws(BluePrintException::class)
105     open fun validateCapabilityAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
106         val capabilities = nodeTemplate.capabilities
107         paths.add("capabilities")
108         capabilities?.forEach { capabilityName, capabilityAssignment ->
109             paths.add(capabilityName)
110
111             val capabilityDefinition = nodeType.capabilities?.get(capabilityName)
112                     ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) capability definition ($capabilityName) " +
113                             "from NodeType(${nodeTemplate.type})")
114
115             validateCapabilityAssignment(nodeTemplateName, capabilityName, capabilityDefinition, capabilityAssignment)
116
117             paths.removeAt(paths.lastIndex)
118         }
119         paths.removeAt(paths.lastIndex)
120     }
121
122     @Throws(BluePrintException::class)
123     open fun validateCapabilityAssignment(nodeTemplateName: String, capabilityName: String,
124                                           capabilityDefinition: CapabilityDefinition, capabilityAssignment: CapabilityAssignment) {
125
126         capabilityAssignment.properties?.let { validatePropertyAssignments(capabilityDefinition.properties!!, capabilityAssignment.properties!!) }
127
128     }
129
130     @Throws(BluePrintException::class)
131     open fun validateRequirementAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
132         val requirements = nodeTemplate.requirements
133         paths.add("requirements")
134         requirements?.forEach { requirementName, requirementAssignment ->
135             paths.add(requirementName)
136             val requirementDefinition = nodeType.requirements?.get(requirementName)
137                     ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) requirement definition ($requirementName) from" +
138                             " NodeType(${nodeTemplate.type})")
139             // Validate Requirement Assignment
140             validateRequirementAssignment(nodeTemplateName, requirementName, requirementDefinition, requirementAssignment)
141             paths.removeAt(paths.lastIndex)
142         }
143         paths.removeAt(paths.lastIndex)
144
145     }
146
147     @Throws(BluePrintException::class)
148     open fun validateRequirementAssignment(nodeTemplateName: String, requirementAssignmentName: String,
149                                            requirementDefinition: RequirementDefinition, requirementAssignment: RequirementAssignment) {
150         log.info("Validating NodeTemplate({}) requirement assignment ({}) ", nodeTemplateName, requirementAssignmentName)
151         val requirementNodeTemplateName = requirementAssignment.node!!
152         val capabilityName = requirementAssignment.capability
153         val relationship = requirementAssignment.relationship!!
154
155         check(BluePrintTypes.validRelationShipDerivedFroms.contains(relationship)) {
156             throw BluePrintException("Failed to get relationship type ($relationship) for NodeTemplate($nodeTemplateName)'s requirement($requirementAssignmentName)")
157         }
158
159         val relationShipNodeTemplate = bluePrintContext!!.serviceTemplate.topologyTemplate?.nodeTemplates?.get(requirementNodeTemplateName)
160                 ?: throw BluePrintException("Failed to get requirement NodeTemplate($requirementNodeTemplateName)'s " +
161                         "for NodeTemplate($nodeTemplateName) requirement($requirementAssignmentName)")
162
163         relationShipNodeTemplate.capabilities?.get(capabilityName)
164                 ?: throw BluePrintException("Failed to get requirement NodeTemplate($requirementNodeTemplateName)'s " +
165                         "capability($capabilityName) for NodeTemplate ($nodeTemplateName)'s requirement($requirementAssignmentName)")
166
167
168     }
169
170     @Throws(BluePrintException::class)
171     open fun validateInterfaceAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
172
173         val interfaces = nodeTemplate.interfaces
174         paths.add("interfaces")
175         interfaces?.forEach { interfaceAssignmentName, interfaceAssignment ->
176             paths.add(interfaceAssignmentName)
177             val interfaceDefinition = nodeType.interfaces?.get(interfaceAssignmentName)
178                     ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) interface definition ($interfaceAssignmentName) from" +
179                             " NodeType(${nodeTemplate.type})")
180
181             validateInterfaceAssignment(nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
182                     interfaceAssignment)
183             paths.removeAt(paths.lastIndex)
184         }
185         paths.removeAt(paths.lastIndex)
186
187
188     }
189
190     @Throws(BluePrintException::class)
191     open fun validateInterfaceAssignment(nodeTemplateName: String, interfaceAssignmentName: String,
192                                          interfaceDefinition: InterfaceDefinition,
193                                          interfaceAssignment: InterfaceAssignment) {
194
195         val operations = interfaceAssignment.operations
196         operations?.let {
197             validateInterfaceOperationsAssignment(nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
198                     interfaceAssignment)
199         }
200
201     }
202
203     @Throws(BluePrintException::class)
204     open fun validateInterfaceOperationsAssignment(nodeTemplateName: String, interfaceAssignmentName: String,
205                                                    interfaceDefinition: InterfaceDefinition,
206                                                    interfaceAssignment: InterfaceAssignment) {
207
208         val operations = interfaceAssignment.operations
209         operations?.let {
210             it.forEach { operationAssignmentName, operationAssignments ->
211
212                 val operationDefinition = interfaceDefinition.operations?.get(operationAssignmentName)
213                         ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) operation definition ($operationAssignmentName)")
214
215                 log.info("Validation NodeTemplate({}) Interface({}) Operation ({})", nodeTemplateName,
216                         interfaceAssignmentName, operationAssignmentName)
217
218                 val inputs = operationAssignments.inputs
219                 val outputs = operationAssignments.outputs
220
221                 inputs?.forEach { propertyName, propertyAssignment ->
222                     val propertyDefinition = operationDefinition.inputs?.get(propertyName)
223                             ?: throw BluePrintException("Failed to get NodeTemplate(nodeTemplateName) operation " +
224                                     "definition (operationAssignmentName) property definition(propertyName)")
225                     // Check the property values with property definition
226                     validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
227                 }
228
229                 outputs?.forEach { propertyName, propertyAssignment ->
230                     val propertyDefinition = operationDefinition.outputs?.get(propertyName)
231                             ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) operation definition ($operationAssignmentName) " +
232                                     "output property definition($propertyName)")
233                     // Check the property values with property definition
234                     validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
235                 }
236
237             }
238         }
239
240     }
241
242     open fun checkValidArtifactType(artifactDefinitionName: String, artifactTypeName: String) {
243
244         val artifactType = bluePrintContext!!.serviceTemplate.artifactTypes?.get(artifactTypeName)
245                 ?: throw BluePrintException("failed to artifactType($artifactTypeName) for ArtifactDefinition($artifactDefinitionName)")
246
247         checkValidArtifactTypeDerivedFrom(artifactTypeName, artifactType.derivedFrom)
248     }
249
250     @Throws(BluePrintException::class)
251     open fun checkValidArtifactTypeDerivedFrom(artifactTypeName: String, derivedFrom: String) {
252         check(BluePrintTypes.validArtifactTypeDerivedFroms.contains(derivedFrom)) {
253             throw BluePrintException("failed to get artifactType($artifactTypeName)'s derivedFrom($derivedFrom) definition")
254         }
255     }
256
257     open fun checkPropertyValue(propertyName: String, propertyDefinition: PropertyDefinition, propertyAssignment: JsonNode) {
258         val propertyType = propertyDefinition.type
259         val isValid: Boolean
260
261         if (BluePrintTypes.validPrimitiveTypes().contains(propertyType)) {
262             isValid = JacksonUtils.checkJsonNodeValueOfPrimitiveType(propertyType, propertyAssignment)
263
264         } else if (BluePrintTypes.validCollectionTypes().contains(propertyType)) {
265
266             val entrySchemaType = propertyDefinition.entrySchema?.type
267                     ?: throw BluePrintException(format("Failed to get EntrySchema type for the collection property ({})", propertyName))
268
269             if (!BluePrintTypes.validPropertyTypes().contains(entrySchemaType)) {
270                 checkPropertyDataType(entrySchemaType, propertyName)
271             }
272             isValid = JacksonUtils.checkJsonNodeValueOfCollectionType(propertyType, propertyAssignment)
273         } else {
274             checkPropertyDataType(propertyType, propertyName)
275             isValid = true
276         }
277
278         check(isValid) {
279             throw BluePrintException("property(propertyName) defined of type(propertyType) is not comptable with the value (propertyAssignment)")
280         }
281     }
282
283     private fun checkPropertyDataType(dataTypeName: String, propertyName: String) {
284
285         val dataType = bluePrintContext!!.serviceTemplate.dataTypes?.get(dataTypeName)
286                 ?: throw BluePrintException("DataType ($dataTypeName) for the property ($propertyName) not found")
287
288         checkValidDataTypeDerivedFrom(propertyName, dataType.derivedFrom)
289
290     }
291
292     private fun checkValidDataTypeDerivedFrom(dataTypeName: String, derivedFrom: String) {
293         check(BluePrintTypes.validDataTypeDerivedFroms.contains(derivedFrom)) {
294             throw BluePrintException("Failed to get DataType($dataTypeName)'s  derivedFrom($derivedFrom) definition ")
295         }
296     }
297
298 }