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 com.att.eelf.configuration.EELFLogger
\r 
  25 import com.att.eelf.configuration.EELFManager
\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 log: EELFLogger = EELFManager.getInstance().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     private val separator: String = BluePrintConstants.PATH_DIVIDER
\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             log.error("validation failed in the path : {}", paths.joinToString(separator), e)
\r 
  72             log.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(separator), e.message))
\r 
  79     @Throws(BluePrintException::class)
\r 
  80     open fun validateMetadata(metaDataMap: MutableMap<String, String>) {
\r 
  81         paths.add("metadata")
\r 
  83         val templateName = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_NAME]
\r 
  84         val templateVersion = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_VERSION]
\r 
  85         val templateTags = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_TAGS]
\r 
  86         val templateAuthor = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_AUTHOR]
\r 
  88         Preconditions.checkArgument(StringUtils.isNotBlank(templateName), "failed to get template name metadata")
\r 
  89         Preconditions.checkArgument(StringUtils.isNotBlank(templateVersion), "failed to get template version metadata")
\r 
  90         Preconditions.checkArgument(StringUtils.isNotBlank(templateTags), "failed to get template tags metadata")
\r 
  91         Preconditions.checkArgument(StringUtils.isNotBlank(templateAuthor), "failed to get template author metadata")
\r 
  92         paths.removeAt(paths.lastIndex)
\r 
  95     @Throws(BluePrintException::class)
\r 
  96     open fun validateArtifactTypes(artifactTypes: MutableMap<String, ArtifactType>) {
\r 
  97         paths.add("artifact_types")
\r 
  98         artifactTypes.forEach { artifactName, artifactType ->
\r 
  99             paths.add(artifactName)
\r 
 100             message.appendln("--> Artifact Type :" + paths.joinToString(separator))
\r 
 101             artifactType.properties?.let { validatePropertyDefinitions(artifactType.properties!!) }
\r 
 102             paths.removeAt(paths.lastIndex)
\r 
 104         paths.removeAt(paths.lastIndex)
\r 
 107     @Throws(BluePrintException::class)
\r 
 108     open fun validateDataTypes(dataTypes: MutableMap<String, DataType>) {
\r 
 109         paths.add("dataTypes")
\r 
 110         dataTypes.forEach { dataTypeName, dataType ->
\r 
 111             paths.add(dataTypeName)
\r 
 112             message.appendln("--> Data Type :" + paths.joinToString(separator))
\r 
 113             dataType.properties?.let { validatePropertyDefinitions(dataType.properties!!) }
\r 
 114             paths.removeAt(paths.lastIndex)
\r 
 116         paths.removeAt(paths.lastIndex)
\r 
 119     @Throws(BluePrintException::class)
\r 
 120     open fun validateNodeTypes(nodeTypes: MutableMap<String, NodeType>) {
\r 
 121         paths.add("nodeTypes")
\r 
 122         nodeTypes.forEach { nodeTypeName, nodeType ->
\r 
 123             // Validate Single Node Type
\r 
 124             validateNodeType(nodeTypeName,nodeType)
\r 
 126         paths.removeAt(paths.lastIndex)
\r 
 129     @Throws(BluePrintException::class)
\r 
 130     open fun validateNodeType(nodeTypeName: String, nodeType: NodeType) {
\r 
 131         paths.add(nodeTypeName)
\r 
 132         message.appendln("--> Node Type :" + paths.joinToString(separator))
\r 
 133         val derivedFrom: String = nodeType.derivedFrom
\r 
 134         //Check Derived From
\r 
 135         checkValidNodeTypesDerivedFrom(derivedFrom)
\r 
 137         nodeType.properties?.let { validatePropertyDefinitions(nodeType.properties!!) }
\r 
 138         nodeType.interfaces?.let { validateInterfaceDefinitions(nodeType.interfaces!!) }
\r 
 139         paths.removeAt(paths.lastIndex)
\r 
 142     @Throws(BluePrintException::class)
\r 
 143     open fun validateTopologyTemplate(topologyTemplate: TopologyTemplate) {
\r 
 144         paths.add("topology")
\r 
 145         message.appendln("--> Topology Template")
\r 
 146         topologyTemplate.inputs?.let { validateInputs(topologyTemplate.inputs!!) }
\r 
 147         topologyTemplate.nodeTemplates?.let { validateNodeTemplates(topologyTemplate.nodeTemplates!!) }
\r 
 148         topologyTemplate.workflows?.let { validateWorkFlows(topologyTemplate.workflows!!) }
\r 
 149         paths.removeAt(paths.lastIndex)
\r 
 152     @Throws(BluePrintException::class)
\r 
 153     open fun validateInputs(inputs: MutableMap<String, PropertyDefinition>) {
\r 
 154         paths.add("inputs")
\r 
 155         message.appendln("---> Input :" + paths.joinToString(separator))
\r 
 156         validatePropertyDefinitions(inputs)
\r 
 157         paths.removeAt(paths.lastIndex)
\r 
 160     @Throws(BluePrintException::class)
\r 
 161     open fun validateNodeTemplates(nodeTemplates: MutableMap<String, NodeTemplate>) {
\r 
 162         paths.add("nodeTemplates")
\r 
 163         nodeTemplates.forEach { nodeTemplateName, nodeTemplate ->
\r 
 164             validateNodeTemplate(nodeTemplateName, nodeTemplate)
\r 
 166         paths.removeAt(paths.lastIndex)
\r 
 169     @Throws(BluePrintException::class)
\r 
 170     open fun validateNodeTemplate(nodeTemplateName : String, nodeTemplate: NodeTemplate) {
\r 
 171         paths.add(nodeTemplateName)
\r 
 172         message.appendln("---> Node Template :" + paths.joinToString(separator))
\r 
 173         val type: String = nodeTemplate.type
\r 
 175         val nodeType: NodeType = serviceTemplate.nodeTypes?.get(type)
\r 
 176                 ?: throw BluePrintException(format("Failed to get node type definition  for node template : {}", nodeTemplateName))
\r 
 178         nodeTemplate.artifacts?.let { validateArtifactDefinitions(nodeTemplate.artifacts!!) }
\r 
 179         nodeTemplate.properties?.let { validatePropertyAssignments(nodeType.properties!!, nodeTemplate.properties!!) }
\r 
 180         nodeTemplate.capabilities?.let { validateCapabilityAssignments(nodeTemplate.capabilities!!) }
\r 
 181         nodeTemplate.requirements?.let { validateRequirementAssignments(nodeTemplate.requirements!!) }
\r 
 182         nodeTemplate.interfaces?.let { validateInterfaceAssignments(nodeTemplate.interfaces!!) }
\r 
 183         paths.removeAt(paths.lastIndex)
\r 
 186     @Throws(BluePrintException::class)
\r 
 187     open fun validateWorkFlows(workflows: MutableMap<String, Workflow>) {
\r 
 188         paths.add("workflows")
\r 
 189         workflows.forEach { workflowName, workflow ->
\r 
 191             // Validate Single workflow
\r 
 192             validateWorkFlow(workflowName, workflow)
\r 
 194         paths.removeAt(paths.lastIndex)
\r 
 197     @Throws(BluePrintException::class)
\r 
 198     open fun validateWorkFlow(workflowName:String, workflow: Workflow) {
\r 
 199         paths.add(workflowName)
\r 
 200         message.appendln("---> Workflow :" + paths.joinToString(separator))
\r 
 201         // Step Validation Start
\r 
 203         workflow.steps?.forEach { stepName, step ->
\r 
 204             paths.add(stepName)
\r 
 205             message.appendln("----> Steps :" + paths.joinToString(separator))
\r 
 206             paths.removeAt(paths.lastIndex)
\r 
 208         paths.removeAt(paths.lastIndex)
\r 
 209         // Step Validation Ends
\r 
 210         paths.removeAt(paths.lastIndex)
\r 
 213     @Throws(BluePrintException::class)
\r 
 214     open fun validatePropertyDefinitions(properties: MutableMap<String, PropertyDefinition>) {
\r 
 215         paths.add("properties")
\r 
 216         properties.forEach { propertyName, propertyDefinition ->
\r 
 217             paths.add(propertyName)
\r 
 218             val dataType: String = propertyDefinition.type
\r 
 220                 BluePrintTypes.validPrimitiveTypes().contains(dataType) -> {
\r 
 223                 BluePrintTypes.validCollectionTypes().contains(dataType) -> {
\r 
 224                     val entrySchemaType: String = propertyDefinition.entrySchema?.type
\r 
 225                             ?: throw BluePrintException(format("Entry schema for data type ({}) for the property ({}) not found", dataType, propertyName))
\r 
 226                     checkPrimitiveOrComplex(entrySchemaType, propertyName)
\r 
 228                 else -> checkPropertyDataType(dataType, propertyName)
\r 
 230             message.appendln("property " + paths.joinToString(separator) + " of type " + dataType)
\r 
 231             paths.removeAt(paths.lastIndex)
\r 
 233         paths.removeAt(paths.lastIndex)
\r 
 236     @Throws(BluePrintException::class)
\r 
 237     open fun validatePropertyAssignments(nodeTypeProperties: MutableMap<String, PropertyDefinition>,
\r 
 238                                          properties: MutableMap<String, JsonNode>) {
\r 
 239         properties.forEach { propertyName, propertyAssignment ->
\r 
 240             val propertyDefinition: PropertyDefinition = nodeTypeProperties[propertyName]
\r 
 241                     ?: throw BluePrintException(format("failed to get definition for the property ({})", propertyName))
\r 
 242             // Check and Validate if Expression Node
\r 
 243             val expressionData = BluePrintExpressionService.getExpressionData(propertyAssignment)
\r 
 244             if (!expressionData.isExpression) {
\r 
 245                 checkPropertyValue(propertyDefinition, propertyAssignment)
\r 
 250     @Throws(BluePrintException::class)
\r 
 251     open fun validateArtifactDefinitions(artifacts: MutableMap<String, ArtifactDefinition>) {
\r 
 252         paths.add("artifacts")
\r 
 253         artifacts.forEach { artifactName, artifactDefinition ->
\r 
 254             paths.add(artifactName)
\r 
 255             message.appendln("Validating artifact " + paths.joinToString(separator))
\r 
 256             val type: String = artifactDefinition.type
\r 
 257                     ?: throw BluePrintException("type is missing for artifact definition :" + artifactName)
\r 
 258             // Check Artifact Type
\r 
 259             checkValidArtifactType(type)
\r 
 261             val file: String = artifactDefinition.file
\r 
 262                     ?: throw BluePrintException(format("file is missing for artifact definition : {}", artifactName))
\r 
 264             paths.removeAt(paths.lastIndex)
\r 
 266         paths.removeAt(paths.lastIndex)
\r 
 269     @Throws(BluePrintException::class)
\r 
 270     open fun validateCapabilityAssignments(capabilities: MutableMap<String, CapabilityAssignment>) {
\r 
 274     @Throws(BluePrintException::class)
\r 
 275     open fun validateRequirementAssignments(requirements: MutableMap<String, RequirementAssignment>) {
\r 
 279     @Throws(BluePrintException::class)
\r 
 280     open fun validateInterfaceAssignments(interfaces: MutableMap<String, InterfaceAssignment>) {
\r 
 284     @Throws(BluePrintException::class)
\r 
 285     open fun validateInterfaceDefinitions(interfaces: MutableMap<String, InterfaceDefinition>) {
\r 
 286         paths.add("interfaces")
\r 
 287         interfaces.forEach { interfaceName, interfaceDefinition ->
\r 
 288             paths.add(interfaceName)
\r 
 289             message.appendln("Validating : " + paths.joinToString(separator))
\r 
 290             interfaceDefinition.operations?.let { validateOperationDefinitions(interfaceDefinition.operations!!) }
\r 
 291             paths.removeAt(paths.lastIndex)
\r 
 293         paths.removeAt(paths.lastIndex)
\r 
 296     @Throws(BluePrintException::class)
\r 
 297     open fun validateOperationDefinitions(operations: MutableMap<String, OperationDefinition>) {
\r 
 298         paths.add("operations")
\r 
 299         operations.forEach { opertaionName, operationDefinition ->
\r 
 300             paths.add(opertaionName)
\r 
 301             message.appendln("Validating : " + paths.joinToString(separator))
\r 
 302             operationDefinition.implementation?.let { validateImplementation(operationDefinition.implementation!!) }
\r 
 303             operationDefinition.inputs?.let { validatePropertyDefinitions(operationDefinition.inputs!!) }
\r 
 304             operationDefinition.outputs?.let { validatePropertyDefinitions(operationDefinition.outputs!!) }
\r 
 305             paths.removeAt(paths.lastIndex)
\r 
 307         paths.removeAt(paths.lastIndex)
\r 
 310     @Throws(BluePrintException::class)
\r 
 311     open fun validateImplementation(implementation: Implementation) {
\r 
 312         checkNotEmptyNThrow(implementation.primary)
\r 
 315     @Throws(BluePrintException::class)
\r 
 316     open fun checkValidNodeType(nodeType : String) {
\r 
 320     @Throws(BluePrintException::class)
\r 
 321     open fun checkValidArtifactType(artifactType: String) {
\r 
 323         serviceTemplate.artifactTypes?.containsKey(artifactType)
\r 
 324                 ?: throw BluePrintException(format("Failed to node type definition for artifact definition : {}", artifactType))
\r 
 327     @Throws(BluePrintException::class)
\r 
 328     open fun checkValidNodeTypesDerivedFrom(derivedFrom: String) {
\r 
 332     private fun checkPropertyValue(propertyDefinition: PropertyDefinition, jsonNode: JsonNode) {
\r 
 333         //log.info("validating path ({}), Property {}, value ({})", paths, propertyDefinition, jsonNode)
\r 
 336     private fun checkPropertyDataType(dataType: String, propertyName: String): Boolean {
\r 
 337         if (checkDataType(dataType)) {
\r 
 340             throw BluePrintException(format("Data type ({}) for the property ({}) not found", dataType, propertyName))
\r 
 344     private fun checkPrimitiveOrComplex(dataType: String, propertyName: String): Boolean {
\r 
 345         if (BluePrintTypes.validPrimitiveTypes().contains(dataType) || checkDataType(dataType)) {
\r 
 348             throw BluePrintException(format("Data type ({}) for the property ({}) is not valid", dataType))
\r 
 352     private fun checkDataType(key: String): Boolean {
\r 
 353         return serviceTemplate.dataTypes?.containsKey(key) ?: false
\r 
 356     private fun checkNodeType(key: String): Boolean {
\r 
 357         return serviceTemplate.nodeTypes?.containsKey(key) ?: false
\r