2 * Copyright © 2017-2018 AT&T Intellectual Property.
3 * Modifications Copyright © 2018 IBM.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package org.onap.ccsdk.cds.controllerblueprints.validation
20 import com.att.eelf.configuration.EELFLogger
21 import com.att.eelf.configuration.EELFManager
22 import com.fasterxml.jackson.databind.JsonNode
23 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
24 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintTypes
25 import org.onap.ccsdk.cds.controllerblueprints.core.data.*
26 import org.onap.ccsdk.cds.controllerblueprints.core.format
27 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintNodeTemplateValidator
28 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintTypeValidatorService
29 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
30 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintExpressionService
31 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
32 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
33 import org.springframework.beans.factory.config.ConfigurableBeanFactory
34 import org.springframework.context.annotation.Scope
35 import org.springframework.stereotype.Service
38 @Service("default-node-template-validator")
39 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
40 open class BluePrintNodeTemplateValidatorImpl(private val bluePrintTypeValidatorService: BluePrintTypeValidatorService) : BluePrintNodeTemplateValidator {
42 private val log: EELFLogger = EELFManager.getInstance().getLogger(BluePrintNodeTemplateValidatorImpl::class.toString())
44 lateinit var bluePrintRuntimeService: BluePrintRuntimeService<*>
45 lateinit var bluePrintContext: BluePrintContext
46 var paths: MutableList<String> = arrayListOf()
48 override fun validate(bluePrintRuntimeService: BluePrintRuntimeService<*>, name: String, nodeTemplate: NodeTemplate) {
49 log.info("Validating NodeTemplate($name)")
51 this.bluePrintRuntimeService = bluePrintRuntimeService
52 this.bluePrintContext = bluePrintRuntimeService.bluePrintContext()
56 val type: String = nodeTemplate.type
58 val nodeType: NodeType = bluePrintContext.serviceTemplate.nodeTypes?.get(type)
59 ?: throw BluePrintException("Failed to get NodeType($type) definition for NodeTemplate($name)")
61 nodeTemplate.properties?.let { validatePropertyAssignments(nodeType.properties!!, nodeTemplate.properties!!) }
62 nodeTemplate.capabilities?.let { validateCapabilityAssignments(nodeType, name, nodeTemplate) }
63 nodeTemplate.requirements?.let { validateRequirementAssignments(nodeType, name, nodeTemplate) }
64 nodeTemplate.interfaces?.let { validateInterfaceAssignments(nodeType, name, nodeTemplate) }
65 nodeTemplate.artifacts?.let { validateArtifactDefinitions(nodeTemplate.artifacts!!) }
67 // Perform Extension Validation
68 validateExtension("$type-node-template-validator", name, nodeTemplate)
70 paths.removeAt(paths.lastIndex)
73 @Throws(BluePrintException::class)
74 open fun validateArtifactDefinitions(artifacts: MutableMap<String, ArtifactDefinition>) {
75 paths.add("artifacts")
76 artifacts.forEach { artifactDefinitionName, artifactDefinition ->
77 bluePrintTypeValidatorService.validateArtifactDefinition(bluePrintRuntimeService,
78 artifactDefinitionName, artifactDefinition)
80 paths.removeAt(paths.lastIndex)
84 @Throws(BluePrintException::class)
85 open fun validatePropertyAssignments(nodeTypeProperties: MutableMap<String, PropertyDefinition>,
86 properties: MutableMap<String, JsonNode>) {
87 properties.forEach { propertyName, propertyAssignment ->
88 val propertyDefinition: PropertyDefinition = nodeTypeProperties[propertyName]
89 ?: throw BluePrintException("failed to get definition for the property ($propertyName)")
91 validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
96 @Throws(BluePrintException::class)
97 open fun validatePropertyAssignment(propertyName: String, propertyDefinition: PropertyDefinition,
98 propertyAssignment: JsonNode) {
99 // Check and Validate if Expression Node
100 val expressionData = BluePrintExpressionService.getExpressionData(propertyAssignment)
101 if (!expressionData.isExpression) {
102 checkPropertyValue(propertyName, propertyDefinition, propertyAssignment)
106 @Throws(BluePrintException::class)
107 open fun validateCapabilityAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
108 val capabilities = nodeTemplate.capabilities
109 paths.add("capabilities")
110 capabilities?.forEach { capabilityName, capabilityAssignment ->
111 paths.add(capabilityName)
113 val capabilityDefinition = nodeType.capabilities?.get(capabilityName)
114 ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) capability definition ($capabilityName) " +
115 "from NodeType(${nodeTemplate.type})")
117 validateCapabilityAssignment(nodeTemplateName, capabilityName, capabilityDefinition, capabilityAssignment)
119 paths.removeAt(paths.lastIndex)
121 paths.removeAt(paths.lastIndex)
124 @Throws(BluePrintException::class)
125 open fun validateCapabilityAssignment(nodeTemplateName: String, capabilityName: String,
126 capabilityDefinition: CapabilityDefinition, capabilityAssignment: CapabilityAssignment) {
128 capabilityAssignment.properties?.let { validatePropertyAssignments(capabilityDefinition.properties!!, capabilityAssignment.properties!!) }
132 @Throws(BluePrintException::class)
133 open fun validateRequirementAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
134 val requirements = nodeTemplate.requirements
135 paths.add("requirements")
136 requirements?.forEach { requirementName, requirementAssignment ->
137 paths.add(requirementName)
138 val requirementDefinition = nodeType.requirements?.get(requirementName)
139 ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) requirement definition ($requirementName) from" +
140 " NodeType(${nodeTemplate.type})")
141 // Validate Requirement Assignment
142 validateRequirementAssignment(nodeTemplateName, requirementName, requirementDefinition, requirementAssignment)
143 paths.removeAt(paths.lastIndex)
145 paths.removeAt(paths.lastIndex)
149 @Throws(BluePrintException::class)
150 open fun validateRequirementAssignment(nodeTemplateName: String, requirementAssignmentName: String,
151 requirementDefinition: RequirementDefinition, requirementAssignment: RequirementAssignment) {
152 log.info("Validating NodeTemplate({}) requirement assignment ({}) ", nodeTemplateName, requirementAssignmentName)
153 val requirementNodeTemplateName = requirementAssignment.node!!
154 val capabilityName = requirementAssignment.capability
155 val relationship = requirementAssignment.relationship!!
157 check(BluePrintTypes.validRelationShipDerivedFroms.contains(relationship)) {
158 throw BluePrintException("Failed to get relationship type ($relationship) for NodeTemplate($nodeTemplateName)'s requirement($requirementAssignmentName)")
161 val relationShipNodeTemplate = bluePrintContext.serviceTemplate.topologyTemplate?.nodeTemplates?.get(requirementNodeTemplateName)
162 ?: throw BluePrintException("Failed to get requirement NodeTemplate($requirementNodeTemplateName)'s " +
163 "for NodeTemplate($nodeTemplateName) requirement($requirementAssignmentName)")
165 relationShipNodeTemplate.capabilities?.get(capabilityName)
166 ?: throw BluePrintException("Failed to get requirement NodeTemplate($requirementNodeTemplateName)'s " +
167 "capability($capabilityName) for NodeTemplate ($nodeTemplateName)'s requirement($requirementAssignmentName)")
172 @Throws(BluePrintException::class)
173 open fun validateInterfaceAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
175 val interfaces = nodeTemplate.interfaces
176 paths.add("interfaces")
177 interfaces?.forEach { interfaceAssignmentName, interfaceAssignment ->
178 paths.add(interfaceAssignmentName)
179 val interfaceDefinition = nodeType.interfaces?.get(interfaceAssignmentName)
180 ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) interface definition ($interfaceAssignmentName) from" +
181 " NodeType(${nodeTemplate.type})")
183 validateInterfaceAssignment(nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
185 paths.removeAt(paths.lastIndex)
187 paths.removeAt(paths.lastIndex)
192 @Throws(BluePrintException::class)
193 open fun validateInterfaceAssignment(nodeTemplateName: String, interfaceAssignmentName: String,
194 interfaceDefinition: InterfaceDefinition,
195 interfaceAssignment: InterfaceAssignment) {
197 val operations = interfaceAssignment.operations
199 validateInterfaceOperationsAssignment(nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
205 @Throws(BluePrintException::class)
206 open fun validateInterfaceOperationsAssignment(nodeTemplateName: String, interfaceAssignmentName: String,
207 interfaceDefinition: InterfaceDefinition,
208 interfaceAssignment: InterfaceAssignment) {
210 val operations = interfaceAssignment.operations
212 it.forEach { operationAssignmentName, operationAssignments ->
214 val operationDefinition = interfaceDefinition.operations?.get(operationAssignmentName)
215 ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) operation definition ($operationAssignmentName)")
217 log.info("Validation NodeTemplate($nodeTemplateName) Interface($interfaceAssignmentName) Operation ($operationAssignmentName)")
219 val inputs = operationAssignments.inputs
220 val outputs = operationAssignments.outputs
222 inputs?.forEach { propertyName, propertyAssignment ->
223 val propertyDefinition = operationDefinition.inputs?.get(propertyName)
224 ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) operation " +
225 "definition ($operationAssignmentName) property definition($propertyName)")
226 // Check the property values with property definition
227 validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
230 outputs?.forEach { propertyName, propertyAssignment ->
231 val propertyDefinition = operationDefinition.outputs?.get(propertyName)
232 ?: throw BluePrintException("Failed to get NodeTemplate($nodeTemplateName) operation definition ($operationAssignmentName) " +
233 "output property definition($propertyName)")
234 // Check the property values with property definition
235 validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
243 open fun checkPropertyValue(propertyName: String, propertyDefinition: PropertyDefinition, propertyAssignment: JsonNode) {
244 val propertyType = propertyDefinition.type
247 if (BluePrintTypes.validPrimitiveTypes().contains(propertyType)) {
248 isValid = JacksonUtils.checkJsonNodeValueOfPrimitiveType(propertyType, propertyAssignment)
250 } else if (BluePrintTypes.validComplexTypes().contains(propertyType)) {
252 } else if (BluePrintTypes.validCollectionTypes().contains(propertyType)) {
254 val entrySchemaType = propertyDefinition.entrySchema?.type
255 ?: throw BluePrintException(format("Failed to get EntrySchema type for the collection property ({})", propertyName))
257 if (!BluePrintTypes.validPropertyTypes().contains(entrySchemaType)) {
258 checkPropertyDataType(entrySchemaType, propertyName)
260 isValid = JacksonUtils.checkJsonNodeValueOfCollectionType(propertyType, propertyAssignment)
262 checkPropertyDataType(propertyType, propertyName)
267 throw BluePrintException("property(propertyName) defined of type(propertyType) is not comptable with the value (propertyAssignment)")
271 private fun checkPropertyDataType(dataTypeName: String, propertyName: String) {
273 val dataType = bluePrintContext.serviceTemplate.dataTypes?.get(dataTypeName)
274 ?: throw BluePrintException("DataType ($dataTypeName) for the property ($propertyName) not found")
276 checkValidDataTypeDerivedFrom(propertyName, dataType.derivedFrom)
280 private fun checkValidDataTypeDerivedFrom(dataTypeName: String, derivedFrom: String) {
281 check(BluePrintTypes.validDataTypeDerivedFroms.contains(derivedFrom)) {
282 throw BluePrintException("Failed to get DataType($dataTypeName)'s derivedFrom($derivedFrom) definition ")
286 private fun validateExtension(referencePrefix: String, name: String, nodeTemplate: NodeTemplate) {
287 val customValidator = bluePrintTypeValidatorService
288 .bluePrintValidator(referencePrefix, BluePrintNodeTemplateValidator::class.java)
290 customValidator?.let {
291 it.validate(bluePrintRuntimeService, name, nodeTemplate)