2 * Copyright © 2017-2018 AT&T Intellectual Property.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 package org.onap.ccsdk.apps.controllerblueprints.core.service
\r
19 import com.fasterxml.jackson.databind.JsonNode
\r
20 import com.google.common.base.Preconditions
\r
21 import org.apache.commons.lang3.StringUtils
\r
22 import org.onap.ccsdk.apps.controllerblueprints.core.*
\r
23 import org.onap.ccsdk.apps.controllerblueprints.core.data.*
\r
24 import org.slf4j.Logger
\r
25 import org.slf4j.LoggerFactory
\r
26 import java.io.Serializable
\r
31 * @author Brinda Santh
\r
33 interface BluePrintValidatorService : Serializable {
\r
35 @Throws(BluePrintException::class)
\r
36 fun validateBlueprint(bluePrintContext: BluePrintContext, properties: MutableMap<String, Any>)
\r
38 @Throws(BluePrintException::class)
\r
39 fun validateBlueprint(serviceTemplate: ServiceTemplate, properties: MutableMap<String, Any>)
\r
42 open class BluePrintValidatorDefaultService : BluePrintValidatorService {
\r
44 val logger: Logger = LoggerFactory.getLogger(BluePrintValidatorDefaultService::class.toString())
\r
46 lateinit var bluePrintContext: BluePrintContext
\r
47 lateinit var serviceTemplate: ServiceTemplate
\r
48 lateinit var properties: MutableMap<String, Any>
\r
49 var message: StringBuilder = StringBuilder()
\r
50 val seperator: String = "/"
\r
51 var paths: MutableList<String> = arrayListOf()
\r
53 @Throws(BluePrintException::class)
\r
54 override fun validateBlueprint(bluePrintContext: BluePrintContext, properties: MutableMap<String, Any>) {
\r
55 validateBlueprint(bluePrintContext.serviceTemplate,properties)
\r
58 @Throws(BluePrintException::class)
\r
59 override fun validateBlueprint(serviceTemplate: ServiceTemplate, properties: MutableMap<String, Any>) {
\r
60 this.bluePrintContext = BluePrintContext(serviceTemplate)
\r
61 this.serviceTemplate = serviceTemplate
\r
62 this.properties = properties
\r
64 message.appendln("-> Config Blueprint")
\r
65 serviceTemplate.metadata?.let { validateMetadata(serviceTemplate.metadata!!) }
\r
66 serviceTemplate.artifactTypes?.let { validateArtifactTypes(serviceTemplate.artifactTypes!!) }
\r
67 serviceTemplate.dataTypes?.let { validateDataTypes(serviceTemplate.dataTypes!!) }
\r
68 serviceTemplate.nodeTypes?.let { validateNodeTypes(serviceTemplate.nodeTypes!!) }
\r
69 serviceTemplate.topologyTemplate?.let { validateTopologyTemplate(serviceTemplate.topologyTemplate!!) }
\r
70 } catch (e: Exception) {
\r
71 logger.error("validation failed in the path : {}", paths.joinToString(seperator), e)
\r
72 logger.error("validation trace message :{} ", message)
\r
73 throw BluePrintException(e,
\r
74 format("failed to validate blueprint on path ({}) with message {}"
\r
75 , paths.joinToString(seperator), e.message))
\r
79 @Throws(BluePrintException::class)
\r
80 open fun validateMetadata(metaDataMap: MutableMap<String, String>) {
\r
81 paths.add("metadata")
\r
82 Preconditions.checkArgument(StringUtils.isNotBlank(metaDataMap[BluePrintConstants.METADATA_TEMPLATE_NAME]), "failed to get template name metadata")
\r
83 Preconditions.checkArgument(StringUtils.isNotBlank(metaDataMap[BluePrintConstants.METADATA_TEMPLATE_VERSION]), "failed to get template version metadata")
\r
84 Preconditions.checkArgument(StringUtils.isNotBlank(metaDataMap[BluePrintConstants.METADATA_TEMPLATE_TAGS]), "failed to get template tags metadata")
\r
85 Preconditions.checkArgument(StringUtils.isNotBlank(metaDataMap[BluePrintConstants.METADATA_TEMPLATE_AUTHOR]), "failed to get template author metadata")
\r
86 Preconditions.checkArgument(StringUtils.isNotBlank(metaDataMap[BluePrintConstants.METADATA_USER_GROUPS]), "failed to get user groups metadata")
\r
87 paths.removeAt(paths.lastIndex)
\r
90 @Throws(BluePrintException::class)
\r
91 open fun validateArtifactTypes(artifactTypes: MutableMap<String, ArtifactType>) {
\r
92 paths.add("artifact_types")
\r
93 artifactTypes.forEach { artifactName, artifactType ->
\r
94 paths.add(artifactName)
\r
95 message.appendln("--> Artifact Type :" + paths.joinToString(seperator))
\r
96 artifactType.properties?.let { validatePropertyDefinitions(artifactType.properties!!) }
\r
97 paths.removeAt(paths.lastIndex)
\r
99 paths.removeAt(paths.lastIndex)
\r
102 @Throws(BluePrintException::class)
\r
103 open fun validateDataTypes(dataTypes: MutableMap<String, DataType>) {
\r
104 paths.add("dataTypes")
\r
105 dataTypes.forEach { dataTypeName, dataType ->
\r
106 paths.add(dataTypeName)
\r
107 message.appendln("--> Data Type :" + paths.joinToString(seperator))
\r
108 dataType.properties?.let { validatePropertyDefinitions(dataType.properties!!) }
\r
109 paths.removeAt(paths.lastIndex)
\r
111 paths.removeAt(paths.lastIndex)
\r
114 @Throws(BluePrintException::class)
\r
115 open fun validateNodeTypes(nodeTypes: MutableMap<String, NodeType>) {
\r
116 paths.add("nodeTypes")
\r
117 nodeTypes.forEach { nodeTypeName, nodeType ->
\r
118 // Validate Single Node Type
\r
119 validateNodeType(nodeTypeName,nodeType)
\r
121 paths.removeAt(paths.lastIndex)
\r
124 @Throws(BluePrintException::class)
\r
125 open fun validateNodeType(nodeTypeName: String, nodeType: NodeType) {
\r
126 paths.add(nodeTypeName)
\r
127 message.appendln("--> Node Type :" + paths.joinToString(seperator))
\r
128 val derivedFrom: String = nodeType.derivedFrom
\r
129 //Check Derived From
\r
130 checkValidNodeTypesDerivedFrom(derivedFrom)
\r
132 nodeType.properties?.let { validatePropertyDefinitions(nodeType.properties!!) }
\r
133 nodeType.interfaces?.let { validateInterfaceDefinitions(nodeType.interfaces!!) }
\r
134 paths.removeAt(paths.lastIndex)
\r
137 @Throws(BluePrintException::class)
\r
138 open fun validateTopologyTemplate(topologyTemplate: TopologyTemplate) {
\r
139 paths.add("topology")
\r
140 message.appendln("--> Topology Template")
\r
141 topologyTemplate.inputs?.let { validateInputs(topologyTemplate.inputs!!) }
\r
142 topologyTemplate.nodeTemplates?.let { validateNodeTemplates(topologyTemplate.nodeTemplates!!) }
\r
143 topologyTemplate.workflows?.let { validateWorkFlows(topologyTemplate.workflows!!) }
\r
144 paths.removeAt(paths.lastIndex)
\r
147 @Throws(BluePrintException::class)
\r
148 open fun validateInputs(inputs: MutableMap<String, PropertyDefinition>) {
\r
149 paths.add("inputs")
\r
150 message.appendln("---> Input :" + paths.joinToString(seperator))
\r
151 validatePropertyDefinitions(inputs)
\r
152 paths.removeAt(paths.lastIndex)
\r
155 @Throws(BluePrintException::class)
\r
156 open fun validateNodeTemplates(nodeTemplates: MutableMap<String, NodeTemplate>) {
\r
157 paths.add("nodeTemplates")
\r
158 nodeTemplates.forEach { nodeTemplateName, nodeTemplate ->
\r
159 validateNodeTemplate(nodeTemplateName, nodeTemplate)
\r
161 paths.removeAt(paths.lastIndex)
\r
164 @Throws(BluePrintException::class)
\r
165 open fun validateNodeTemplate(nodeTemplateName : String, nodeTemplate: NodeTemplate) {
\r
166 paths.add(nodeTemplateName)
\r
167 message.appendln("---> Node Template :" + paths.joinToString(seperator))
\r
168 val type: String = nodeTemplate.type
\r
170 val nodeType: NodeType = serviceTemplate.nodeTypes?.get(type)
\r
171 ?: throw BluePrintException(format("Failed to get node type definition for node template : {}", nodeTemplateName))
\r
173 nodeTemplate.artifacts?.let { validateArtifactDefinitions(nodeTemplate.artifacts!!) }
\r
174 nodeTemplate.properties?.let { validatePropertyAssignments(nodeType.properties!!, nodeTemplate.properties!!) }
\r
175 nodeTemplate.capabilities?.let { validateCapabilityAssignments(nodeTemplate.capabilities!!) }
\r
176 nodeTemplate.requirements?.let { validateRequirementAssignments(nodeTemplate.requirements!!) }
\r
177 nodeTemplate.interfaces?.let { validateInterfaceAssignments(nodeTemplate.interfaces!!) }
\r
178 paths.removeAt(paths.lastIndex)
\r
181 @Throws(BluePrintException::class)
\r
182 open fun validateWorkFlows(workflows: MutableMap<String, Workflow>) {
\r
183 paths.add("workflows")
\r
184 workflows.forEach { workflowName, workflow ->
\r
186 // Validate Single workflow
\r
187 validateWorkFlow(workflowName, workflow)
\r
189 paths.removeAt(paths.lastIndex)
\r
192 @Throws(BluePrintException::class)
\r
193 open fun validateWorkFlow(workflowName:String, workflow: Workflow) {
\r
194 paths.add(workflowName)
\r
195 message.appendln("---> Workflow :" + paths.joinToString(seperator))
\r
196 // Step Validation Start
\r
198 workflow.steps?.forEach { stepName, step ->
\r
199 paths.add(stepName)
\r
200 message.appendln("----> Steps :" + paths.joinToString(seperator))
\r
201 paths.removeAt(paths.lastIndex)
\r
203 paths.removeAt(paths.lastIndex)
\r
204 // Step Validation Ends
\r
205 paths.removeAt(paths.lastIndex)
\r
208 @Throws(BluePrintException::class)
\r
209 open fun validatePropertyDefinitions(properties: MutableMap<String, PropertyDefinition>) {
\r
210 paths.add("properties")
\r
211 properties.forEach { propertyName, propertyDefinition ->
\r
212 paths.add(propertyName)
\r
213 val dataType: String = propertyDefinition.type!!
\r
214 if (BluePrintTypes.validPrimitiveTypes().contains(dataType)) {
\r
216 } else if (BluePrintTypes.validCollectionTypes().contains(dataType)) {
\r
217 val entrySchemaType: String = propertyDefinition.entrySchema?.type
\r
218 ?: throw BluePrintException(format("Entry schema for data type ({}) for the property ({}) not found", dataType, propertyName))
\r
219 checkPrimitiveOrComplex(entrySchemaType, propertyName)
\r
221 checkPropertyDataType(dataType, propertyName)
\r
223 message.appendln("property " + paths.joinToString(seperator) + " of type " + dataType)
\r
224 paths.removeAt(paths.lastIndex)
\r
226 paths.removeAt(paths.lastIndex)
\r
229 @Throws(BluePrintException::class)
\r
230 open fun validatePropertyAssignments(nodeTypeProperties: MutableMap<String, PropertyDefinition>,
\r
231 properties: MutableMap<String, JsonNode>) {
\r
232 properties.forEach { propertyName, propertyAssignment ->
\r
233 val propertyDefinition: PropertyDefinition = nodeTypeProperties[propertyName]
\r
234 ?: throw BluePrintException(format("failed to get definition for the property ({})", propertyName))
\r
235 // Check and Validate if Expression Node
\r
236 val expressionData = BluePrintExpressionService.getExpressionData(propertyAssignment)
\r
237 if (!expressionData.isExpression) {
\r
238 checkPropertyValue(propertyDefinition, propertyAssignment)
\r
243 @Throws(BluePrintException::class)
\r
244 open fun validateArtifactDefinitions(artifacts: MutableMap<String, ArtifactDefinition>) {
\r
245 paths.add("artifacts")
\r
246 artifacts.forEach { artifactName, artifactDefinition ->
\r
247 paths.add(artifactName)
\r
248 message.appendln("Validating artifact " + paths.joinToString(seperator))
\r
249 val type: String = artifactDefinition.type
\r
250 ?: throw BluePrintException("type is missing for artifact definition :" + artifactName)
\r
251 // Check Artifact Type
\r
252 checkValidArtifactType(type)
\r
254 val file: String = artifactDefinition.file
\r
255 ?: throw BluePrintException(format("file is missing for artifact definition : {}", artifactName))
\r
257 paths.removeAt(paths.lastIndex)
\r
259 paths.removeAt(paths.lastIndex)
\r
262 @Throws(BluePrintException::class)
\r
263 open fun validateCapabilityAssignments(capabilities: MutableMap<String, CapabilityAssignment>) {
\r
267 @Throws(BluePrintException::class)
\r
268 open fun validateRequirementAssignments(requirements: MutableMap<String, RequirementAssignment>) {
\r
272 @Throws(BluePrintException::class)
\r
273 open fun validateInterfaceAssignments(interfaces: MutableMap<String, InterfaceAssignment>) {
\r
277 @Throws(BluePrintException::class)
\r
278 open fun validateInterfaceDefinitions(interfaces: MutableMap<String, InterfaceDefinition>) {
\r
279 paths.add("interfaces")
\r
280 interfaces.forEach { interfaceName, interfaceDefinition ->
\r
281 paths.add(interfaceName)
\r
282 message.appendln("Validating : " + paths.joinToString(seperator))
\r
283 interfaceDefinition.operations?.let { validateOperationDefinitions(interfaceDefinition.operations!!) }
\r
284 paths.removeAt(paths.lastIndex)
\r
286 paths.removeAt(paths.lastIndex)
\r
289 @Throws(BluePrintException::class)
\r
290 open fun validateOperationDefinitions(operations: MutableMap<String, OperationDefinition>) {
\r
291 paths.add("operations")
\r
292 operations.forEach { opertaionName, operationDefinition ->
\r
293 paths.add(opertaionName)
\r
294 message.appendln("Validating : " + paths.joinToString(seperator))
\r
295 operationDefinition.implementation?.let { validateImplementation(operationDefinition.implementation!!) }
\r
296 operationDefinition.inputs?.let { validatePropertyDefinitions(operationDefinition.inputs!!) }
\r
297 operationDefinition.outputs?.let { validatePropertyDefinitions(operationDefinition.outputs!!) }
\r
298 paths.removeAt(paths.lastIndex)
\r
300 paths.removeAt(paths.lastIndex)
\r
303 @Throws(BluePrintException::class)
\r
304 open fun validateImplementation(implementation: Implementation) {
\r
305 checkNotEmptyNThrow(implementation.primary)
\r
308 @Throws(BluePrintException::class)
\r
309 open fun checkValidNodeType(nodeType : String) {
\r
313 @Throws(BluePrintException::class)
\r
314 open fun checkValidArtifactType(artifactType: String) {
\r
316 serviceTemplate.artifactTypes?.containsKey(artifactType)
\r
317 ?: throw BluePrintException(format("Failed to node type definition for artifact definition : {}", artifactType))
\r
320 @Throws(BluePrintException::class)
\r
321 open fun checkValidNodeTypesDerivedFrom(derivedFrom: String) {
\r
325 private fun checkPropertyValue(propertyDefinition: PropertyDefinition, jsonNode: JsonNode) {
\r
326 //logger.info("validating path ({}), Property {}, value ({})", paths, propertyDefinition, jsonNode)
\r
329 private fun checkPropertyDataType(dataType: String, propertyName: String): Boolean {
\r
330 if (checkDataType(dataType)) {
\r
333 throw BluePrintException(format("Data type ({}) for the property ({}) not found", dataType, propertyName))
\r
337 private fun checkPrimitiveOrComplex(dataType: String, propertyName: String): Boolean {
\r
338 if (BluePrintTypes.validPrimitiveTypes().contains(dataType) || checkDataType(dataType)) {
\r
341 throw BluePrintException(format("Data type ({}) for the property ({}) is not valid", dataType))
\r
345 private fun checkDataType(key: String): Boolean {
\r
346 return serviceTemplate.dataTypes?.containsKey(key) ?: false
\r
349 private fun checkNodeType(key: String): Boolean {
\r
350 return serviceTemplate.nodeTypes?.containsKey(key) ?: false
\r