Revert "Renaming Files having BluePrint to have Blueprint"
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / blueprints / blueprint-core / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / core / service / BluePrintValidatorService.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2018 IBM.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 package org.onap.ccsdk.cds.controllerblueprints.core.service
19
20 import com.fasterxml.jackson.databind.JsonNode
21 import com.google.common.base.Preconditions
22 import org.apache.commons.lang3.StringUtils
23 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
24 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
25 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintTypes
26 import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
27 import org.onap.ccsdk.cds.controllerblueprints.core.data.ArtifactDefinition
28 import org.onap.ccsdk.cds.controllerblueprints.core.data.ArtifactType
29 import org.onap.ccsdk.cds.controllerblueprints.core.data.CapabilityAssignment
30 import org.onap.ccsdk.cds.controllerblueprints.core.data.CapabilityDefinition
31 import org.onap.ccsdk.cds.controllerblueprints.core.data.DataType
32 import org.onap.ccsdk.cds.controllerblueprints.core.data.Implementation
33 import org.onap.ccsdk.cds.controllerblueprints.core.data.InterfaceAssignment
34 import org.onap.ccsdk.cds.controllerblueprints.core.data.InterfaceDefinition
35 import org.onap.ccsdk.cds.controllerblueprints.core.data.NodeTemplate
36 import org.onap.ccsdk.cds.controllerblueprints.core.data.NodeType
37 import org.onap.ccsdk.cds.controllerblueprints.core.data.OperationDefinition
38 import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition
39 import org.onap.ccsdk.cds.controllerblueprints.core.data.RequirementAssignment
40 import org.onap.ccsdk.cds.controllerblueprints.core.data.RequirementDefinition
41 import org.onap.ccsdk.cds.controllerblueprints.core.data.ServiceTemplate
42 import org.onap.ccsdk.cds.controllerblueprints.core.data.TopologyTemplate
43 import org.onap.ccsdk.cds.controllerblueprints.core.data.Workflow
44 import org.onap.ccsdk.cds.controllerblueprints.core.format
45 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
46 import org.slf4j.LoggerFactory
47 import java.io.Serializable
48
49 /**
50  *
51  *
52  * @author Brinda Santh
53  */
54 interface BluePrintValidatorService : Serializable {
55
56     @Throws(BluePrintException::class)
57     fun validateBlueprint(bluePrintContext: BluePrintContext, properties: MutableMap<String, Any>)
58
59     @Throws(BluePrintException::class)
60     fun validateBlueprint(serviceTemplate: ServiceTemplate, properties: MutableMap<String, Any>)
61 }
62
63 @Deprecated("Decomposed implementation moved to blueprint-validation module")
64 open class BluePrintValidatorDefaultService : BluePrintValidatorService {
65
66     val log = LoggerFactory.getLogger(BluePrintValidatorDefaultService::class.toString())
67
68     lateinit var bluePrintContext: BluePrintContext
69     lateinit var serviceTemplate: ServiceTemplate
70     lateinit var properties: MutableMap<String, Any>
71     var message: StringBuilder = StringBuilder()
72     private val separator: String = BluePrintConstants.PATH_DIVIDER
73     var paths: MutableList<String> = arrayListOf()
74
75     @Throws(BluePrintException::class)
76     override fun validateBlueprint(bluePrintContext: BluePrintContext, properties: MutableMap<String, Any>) {
77         validateBlueprint(bluePrintContext.serviceTemplate, properties)
78     }
79
80     @Throws(BluePrintException::class)
81     override fun validateBlueprint(serviceTemplate: ServiceTemplate, properties: MutableMap<String, Any>) {
82         this.bluePrintContext = BluePrintContext(serviceTemplate)
83         this.serviceTemplate = serviceTemplate
84         this.properties = properties
85         try {
86             message.appendln("-> Config Blueprint")
87             serviceTemplate.metadata?.let { validateMetadata(serviceTemplate.metadata!!) }
88             serviceTemplate.artifactTypes?.let { validateArtifactTypes(serviceTemplate.artifactTypes!!) }
89             serviceTemplate.dataTypes?.let { validateDataTypes(serviceTemplate.dataTypes!!) }
90             serviceTemplate.nodeTypes?.let { validateNodeTypes(serviceTemplate.nodeTypes!!) }
91             serviceTemplate.topologyTemplate?.let { validateTopologyTemplate(serviceTemplate.topologyTemplate!!) }
92         } catch (e: Exception) {
93             log.error("validation failed in the path : {}", paths.joinToString(separator), e)
94             log.error("validation trace message :{} ", message)
95             throw BluePrintException(
96                 e,
97                 format("failed to validate blueprint on path ({}) with message {}", paths.joinToString(separator), e.message)
98             )
99         }
100     }
101
102     @Throws(BluePrintException::class)
103     open fun validateMetadata(metaDataMap: MutableMap<String, String>) {
104         paths.add("metadata")
105
106         val templateName = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_NAME]
107         val templateVersion = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_VERSION]
108         val templateTags = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_TAGS]
109         val templateAuthor = metaDataMap[BluePrintConstants.METADATA_TEMPLATE_AUTHOR]
110
111         Preconditions.checkArgument(StringUtils.isNotBlank(templateName), "failed to get template name metadata")
112         Preconditions.checkArgument(StringUtils.isNotBlank(templateVersion), "failed to get template version metadata")
113         Preconditions.checkArgument(StringUtils.isNotBlank(templateTags), "failed to get template tags metadata")
114         Preconditions.checkArgument(StringUtils.isNotBlank(templateAuthor), "failed to get template author metadata")
115         paths.removeAt(paths.lastIndex)
116     }
117
118     @Throws(BluePrintException::class)
119     open fun validateArtifactTypes(artifactTypes: MutableMap<String, ArtifactType>) {
120         paths.add("artifact_types")
121         artifactTypes.forEach { artifactName, artifactType ->
122             paths.add(artifactName)
123             message.appendln("--> Artifact Type :" + paths.joinToString(separator))
124             artifactType.properties?.let { validatePropertyDefinitions(artifactType.properties!!) }
125             paths.removeAt(paths.lastIndex)
126         }
127         paths.removeAt(paths.lastIndex)
128     }
129
130     @Throws(BluePrintException::class)
131     open fun validateDataTypes(dataTypes: MutableMap<String, DataType>) {
132         paths.add("dataTypes")
133         dataTypes.forEach { dataTypeName, dataType ->
134             paths.add(dataTypeName)
135             message.appendln("--> DataType :" + paths.joinToString(separator))
136             dataType.properties?.let { validatePropertyDefinitions(dataType.properties!!) }
137             paths.removeAt(paths.lastIndex)
138         }
139         paths.removeAt(paths.lastIndex)
140     }
141
142     @Throws(BluePrintException::class)
143     open fun validateNodeTypes(nodeTypes: MutableMap<String, NodeType>) {
144         paths.add("nodeTypes")
145         nodeTypes.forEach { nodeTypeName, nodeType ->
146             // Validate Single Node Type
147             validateNodeType(nodeTypeName, nodeType)
148         }
149         paths.removeAt(paths.lastIndex)
150     }
151
152     @Throws(BluePrintException::class)
153     open fun validateNodeType(nodeTypeName: String, nodeType: NodeType) {
154         paths.add(nodeTypeName)
155         message.appendln("--> Node Type :" + paths.joinToString(separator))
156         val derivedFrom: String = nodeType.derivedFrom
157         // Check Derived From
158         checkValidNodeTypesDerivedFrom(nodeTypeName, derivedFrom)
159
160         if (!BluePrintTypes.rootNodeTypes().contains(derivedFrom)) {
161             serviceTemplate.nodeTypes?.get(derivedFrom)
162                 ?: throw BluePrintException(
163                     format(
164                         "Failed to get derivedFrom NodeType({})'s for NodeType({}) ",
165                         derivedFrom, nodeTypeName
166                     )
167                 )
168         }
169
170         nodeType.properties?.let { validatePropertyDefinitions(nodeType.properties!!) }
171         nodeType.capabilities?.let { validateCapabilityDefinitions(nodeTypeName, nodeType) }
172         nodeType.requirements?.let { validateRequirementDefinitions(nodeTypeName, nodeType) }
173         nodeType.interfaces?.let { validateInterfaceDefinitions(nodeType.interfaces!!) }
174         paths.removeAt(paths.lastIndex)
175     }
176
177     @Throws(BluePrintException::class)
178     open fun checkValidNodeTypesDerivedFrom(nodeTypeName: String, derivedFrom: String) {
179         check(BluePrintTypes.validNodeTypeDerivedFroms.contains(derivedFrom)) {
180             throw BluePrintException(format("Failed to get node type ({})'s  derivedFrom({}) definition ", nodeTypeName, derivedFrom))
181         }
182     }
183
184     @Throws(BluePrintException::class)
185     open fun validateTopologyTemplate(topologyTemplate: TopologyTemplate) {
186         paths.add("topology")
187         message.appendln("--> Topology Template")
188         topologyTemplate.inputs?.let { validateInputs(topologyTemplate.inputs!!) }
189         topologyTemplate.nodeTemplates?.let { validateNodeTemplates(topologyTemplate.nodeTemplates!!) }
190         topologyTemplate.workflows?.let { validateWorkFlows(topologyTemplate.workflows!!) }
191         paths.removeAt(paths.lastIndex)
192     }
193
194     @Throws(BluePrintException::class)
195     open fun validateInputs(inputs: MutableMap<String, PropertyDefinition>) {
196         paths.add("inputs")
197         message.appendln("---> Input :" + paths.joinToString(separator))
198         validatePropertyDefinitions(inputs)
199         paths.removeAt(paths.lastIndex)
200     }
201
202     @Throws(BluePrintException::class)
203     open fun validateNodeTemplates(nodeTemplates: MutableMap<String, NodeTemplate>) {
204         paths.add("nodeTemplates")
205         nodeTemplates.forEach { nodeTemplateName, nodeTemplate ->
206             validateNodeTemplate(nodeTemplateName, nodeTemplate)
207         }
208         paths.removeAt(paths.lastIndex)
209     }
210
211     @Throws(BluePrintException::class)
212     open fun validateNodeTemplate(nodeTemplateName: String, nodeTemplate: NodeTemplate) {
213         paths.add(nodeTemplateName)
214         message.appendln("---> NodeTemplate :" + paths.joinToString(separator))
215         val type: String = nodeTemplate.type
216
217         val nodeType: NodeType = serviceTemplate.nodeTypes?.get(type)
218             ?: throw BluePrintException(format("Failed to get NodeType({}) definition for NodeTemplate({})", type, nodeTemplateName))
219
220         nodeTemplate.artifacts?.let { validateArtifactDefinitions(nodeTemplate.artifacts!!) }
221         nodeTemplate.properties?.let { validatePropertyAssignments(nodeType.properties!!, nodeTemplate.properties!!) }
222         nodeTemplate.capabilities?.let { validateCapabilityAssignments(nodeType, nodeTemplateName, nodeTemplate) }
223         nodeTemplate.requirements?.let { validateRequirementAssignments(nodeType, nodeTemplateName, nodeTemplate) }
224         nodeTemplate.interfaces?.let { validateInterfaceAssignments(nodeType, nodeTemplateName, nodeTemplate) }
225         paths.removeAt(paths.lastIndex)
226     }
227
228     @Throws(BluePrintException::class)
229     open fun validateArtifactDefinitions(artifacts: MutableMap<String, ArtifactDefinition>) {
230         paths.add("artifacts")
231         artifacts.forEach { artifactDefinitionName, artifactDefinition ->
232             paths.add(artifactDefinitionName)
233             message.appendln("Validating artifact " + paths.joinToString(separator))
234             val type: String = artifactDefinition.type
235                 ?: throw BluePrintException(format("type is missing for ArtifactDefinition({})", artifactDefinitionName))
236             // Check Artifact Type
237             checkValidArtifactType(artifactDefinitionName, type)
238
239             val file: String = artifactDefinition.file
240                 ?: throw BluePrintException(format("file is missing for ArtifactDefinition({})", artifactDefinitionName))
241
242             paths.removeAt(paths.lastIndex)
243         }
244         paths.removeAt(paths.lastIndex)
245     }
246
247     @Throws(BluePrintException::class)
248     open fun validateWorkFlows(workflows: MutableMap<String, Workflow>) {
249         paths.add("workflows")
250         workflows.forEach { workflowName, workflow ->
251
252             // Validate Single workflow
253             validateWorkFlow(workflowName, workflow)
254         }
255         paths.removeAt(paths.lastIndex)
256     }
257
258     @Throws(BluePrintException::class)
259     open fun validateWorkFlow(workflowName: String, workflow: Workflow) {
260         paths.add(workflowName)
261         message.appendln("---> Workflow :" + paths.joinToString(separator))
262         // Step Validation Start
263         paths.add("steps")
264         workflow.steps?.forEach { stepName, _ ->
265             paths.add(stepName)
266             message.appendln("----> Steps :" + paths.joinToString(separator))
267             paths.removeAt(paths.lastIndex)
268         }
269         paths.removeAt(paths.lastIndex)
270         // Step Validation Ends
271         paths.removeAt(paths.lastIndex)
272     }
273
274     @Throws(BluePrintException::class)
275     open fun validatePropertyDefinitions(properties: MutableMap<String, PropertyDefinition>) {
276         paths.add("properties")
277         properties.forEach { propertyName, propertyDefinition ->
278             paths.add(propertyName)
279             val dataType: String = propertyDefinition.type
280             when {
281                 BluePrintTypes.validPrimitiveTypes().contains(dataType) -> {
282                     // Do Nothing
283                 }
284                 BluePrintTypes.validCollectionTypes().contains(dataType) -> {
285                     val entrySchemaType: String = propertyDefinition.entrySchema?.type
286                         ?: throw BluePrintException(format("Entry schema for DataType ({}) for the property ({}) not found", dataType, propertyName))
287                     checkPrimitiveOrComplex(entrySchemaType, propertyName)
288                 }
289                 else -> checkPropertyDataType(dataType, propertyName)
290             }
291             message.appendln("property " + paths.joinToString(separator) + " of type " + dataType)
292             paths.removeAt(paths.lastIndex)
293         }
294         paths.removeAt(paths.lastIndex)
295     }
296
297     @Throws(BluePrintException::class)
298     open fun validatePropertyAssignments(
299         nodeTypeProperties: MutableMap<String, PropertyDefinition>,
300         properties: MutableMap<String, JsonNode>
301     ) {
302         properties.forEach { propertyName, propertyAssignment ->
303             val propertyDefinition: PropertyDefinition = nodeTypeProperties[propertyName]
304                 ?: throw BluePrintException(format("failed to get definition for the property ({})", propertyName))
305
306             validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
307         }
308     }
309
310     @Throws(BluePrintException::class)
311     open fun validatePropertyAssignment(
312         propertyName: String,
313         propertyDefinition: PropertyDefinition,
314         propertyAssignment: JsonNode
315     ) {
316         // Check and Validate if Expression Node
317         val expressionData = BluePrintExpressionService.getExpressionData(propertyAssignment)
318         if (!expressionData.isExpression) {
319             checkPropertyValue(propertyName, propertyDefinition, propertyAssignment)
320         }
321     }
322
323     @Throws(BluePrintException::class)
324     open fun validateCapabilityAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
325         val capabilities = nodeTemplate.capabilities
326         paths.add("capabilities")
327         capabilities?.forEach { capabilityName, capabilityAssignment ->
328             paths.add(capabilityName)
329
330             val capabilityDefinition = nodeType.capabilities?.get(capabilityName)
331                 ?: throw BluePrintException(
332                     format(
333                         "Failed to get NodeTemplate({}) capability definition ({}) " +
334                             "from NodeType({}) ",
335                         nodeTemplateName, capabilityName, nodeTemplate.type
336                     )
337                 )
338
339             validateCapabilityAssignment(nodeTemplateName, capabilityName, capabilityDefinition, capabilityAssignment)
340
341             paths.removeAt(paths.lastIndex)
342         }
343         paths.removeAt(paths.lastIndex)
344     }
345
346     @Throws(BluePrintException::class)
347     open fun validateCapabilityAssignment(
348         nodeTemplateName: String,
349         capabilityName: String,
350         capabilityDefinition: CapabilityDefinition,
351         capabilityAssignment: CapabilityAssignment
352     ) {
353
354         capabilityAssignment.properties?.let { validatePropertyAssignments(capabilityDefinition.properties!!, capabilityAssignment.properties!!) }
355     }
356
357     @Throws(BluePrintException::class)
358     open fun validateRequirementAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
359         val requirements = nodeTemplate.requirements
360         paths.add("requirements")
361         requirements?.forEach { requirementName, requirementAssignment ->
362             paths.add(requirementName)
363             val requirementDefinition = nodeType.requirements?.get(requirementName)
364                 ?: throw BluePrintException(
365                     format(
366                         "Failed to get NodeTemplate({}) requirement definition ({}) from" +
367                             " NodeType({}) ",
368                         nodeTemplateName, requirementName, nodeTemplate.type
369                     )
370                 )
371             // Validate Requirement Assignment
372             validateRequirementAssignment(nodeTemplateName, requirementName, requirementDefinition, requirementAssignment)
373             paths.removeAt(paths.lastIndex)
374         }
375         paths.removeAt(paths.lastIndex)
376     }
377
378     @Throws(BluePrintException::class)
379     open fun validateRequirementAssignment(
380         nodeTemplateName: String,
381         requirementAssignmentName: String,
382         requirementDefinition: RequirementDefinition,
383         requirementAssignment: RequirementAssignment
384     ) {
385         log.info("Validating NodeTemplate({}) requirement assignment ({}) ", nodeTemplateName, requirementAssignmentName)
386         val requirementNodeTemplateName = requirementAssignment.node!!
387         val capabilityName = requirementAssignment.capability
388         val relationship = requirementAssignment.relationship!!
389
390         check(BluePrintTypes.validRelationShipDerivedFroms.contains(relationship)) {
391             throw BluePrintException(
392                 format(
393                     "Failed to get relationship type ({}) for NodeTemplate({})'s requirement({}) ",
394                     relationship, nodeTemplateName, requirementAssignmentName
395                 )
396             )
397         }
398
399         val relationShipNodeTemplate = serviceTemplate.topologyTemplate?.nodeTemplates?.get(requirementNodeTemplateName)
400             ?: throw BluePrintException(
401                 format(
402                     "Failed to get requirement NodeTemplate({})'s for NodeTemplate({}) requirement({}) ",
403                     requirementNodeTemplateName, nodeTemplateName, requirementAssignmentName
404                 )
405             )
406
407         relationShipNodeTemplate.capabilities?.get(capabilityName)
408             ?: throw BluePrintException(
409                 format(
410                     "Failed to get requirement NodeTemplate({})'s capability({}) for NodeTemplate ({})'s requirement({}) ",
411                     requirementNodeTemplateName, capabilityName, nodeTemplateName, requirementAssignmentName
412                 )
413             )
414     }
415
416     @Throws(BluePrintException::class)
417     open fun validateInterfaceAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
418
419         val interfaces = nodeTemplate.interfaces
420         paths.add("interfaces")
421         interfaces?.forEach { interfaceAssignmentName, interfaceAssignment ->
422             paths.add(interfaceAssignmentName)
423             val interfaceDefinition = nodeType.interfaces?.get(interfaceAssignmentName)
424                 ?: throw BluePrintException(
425                     format(
426                         "Failed to get NodeTemplate({}) interface definition ({}) from" +
427                             " NodeType({}) ",
428                         nodeTemplateName, interfaceAssignmentName, nodeTemplate.type
429                     )
430                 )
431
432             validateInterfaceAssignment(
433                 nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
434                 interfaceAssignment
435             )
436             paths.removeAt(paths.lastIndex)
437         }
438         paths.removeAt(paths.lastIndex)
439     }
440
441     @Throws(BluePrintException::class)
442     open fun validateInterfaceAssignment(
443         nodeTemplateName: String,
444         interfaceAssignmentName: String,
445         interfaceDefinition: InterfaceDefinition,
446         interfaceAssignment: InterfaceAssignment
447     ) {
448
449         val operations = interfaceAssignment.operations
450         operations?.let {
451             validateInterfaceOperationsAssignment(
452                 nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
453                 interfaceAssignment
454             )
455         }
456     }
457
458     @Throws(BluePrintException::class)
459     open fun validateInterfaceOperationsAssignment(
460         nodeTemplateName: String,
461         interfaceAssignmentName: String,
462         interfaceDefinition: InterfaceDefinition,
463         interfaceAssignment: InterfaceAssignment
464     ) {
465
466         val operations = interfaceAssignment.operations
467         operations?.let {
468             it.forEach { operationAssignmentName, operationAssignments ->
469
470                 val operationDefinition = interfaceDefinition.operations?.get(operationAssignmentName)
471                     ?: throw BluePrintException(
472                         format(
473                             "Failed to get NodeTemplate({}) operation definition ({}) ",
474                             nodeTemplateName, operationAssignmentName
475                         )
476                     )
477
478                 log.info(
479                     "Validation NodeTemplate({}) Interface({}) Operation ({})", nodeTemplateName,
480                     interfaceAssignmentName, operationAssignmentName
481                 )
482
483                 val inputs = operationAssignments.inputs
484                 val outputs = operationAssignments.outputs
485
486                 inputs?.forEach { propertyName, propertyAssignment ->
487                     val propertyDefinition = operationDefinition.inputs?.get(propertyName)
488                         ?: throw BluePrintException(
489                             format(
490                                 "Failed to get NodeTemplate({}) operation definition ({}) " +
491                                     "property definition({})",
492                                 nodeTemplateName, operationAssignmentName, propertyName
493                             )
494                         )
495                     // Check the property values with property definition
496                     validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
497                 }
498
499                 outputs?.forEach { propertyName, propertyAssignment ->
500                     val propertyDefinition = operationDefinition.outputs?.get(propertyName)
501                         ?: throw BluePrintException(
502                             format(
503                                 "Failed to get NodeTemplate({}) operation definition ({}) " +
504                                     "output property definition({})",
505                                 nodeTemplateName, operationAssignmentName,
506                                 propertyName
507                             )
508                         )
509                     // Check the property values with property definition
510                     validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
511                 }
512             }
513         }
514     }
515
516     @Throws(BluePrintException::class)
517     open fun validateCapabilityDefinitions(nodeTypeName: String, nodeType: NodeType) {
518         val capabilities = nodeType.capabilities
519         paths.add("capabilities")
520         capabilities?.forEach { capabilityName, capabilityDefinition ->
521             paths.add(capabilityName)
522
523             validateCapabilityDefinition(nodeTypeName, nodeType, capabilityName, capabilityDefinition)
524
525             paths.removeAt(paths.lastIndex)
526         }
527         paths.removeAt(paths.lastIndex)
528     }
529
530     @Throws(BluePrintException::class)
531     open fun validateCapabilityDefinition(
532         nodeTypeName: String,
533         nodeType: NodeType,
534         capabilityName: String,
535         capabilityDefinition: CapabilityDefinition
536     ) {
537         val capabilityType = capabilityDefinition.type
538         check(BluePrintTypes.validCapabilityTypes.contains(capabilityType)) {
539             throw BluePrintException(
540                 format(
541                     "Failed to get CapabilityType({}) for NodeType({})",
542                     capabilityType, nodeTypeName
543                 )
544             )
545         }
546     }
547
548     @Throws(BluePrintException::class)
549     open fun validateRequirementDefinitions(nodeName: String, nodeType: NodeType) {
550         paths.add("requirements")
551         val requirements = nodeType.requirements
552
553         requirements?.forEach { requirementDefinitionName, requirementDefinition ->
554             paths.add(requirementDefinitionName)
555             message.appendln("Validating : " + paths.joinToString(separator))
556             validateRequirementDefinition(nodeName, nodeType, requirementDefinitionName, requirementDefinition)
557             paths.removeAt(paths.lastIndex)
558         }
559         paths.removeAt(paths.lastIndex)
560     }
561
562     @Throws(BluePrintException::class)
563     open fun validateRequirementDefinition(
564         nodeTypeName: String,
565         nodeType: NodeType,
566         requirementDefinitionName: String,
567         requirementDefinition: RequirementDefinition
568     ) {
569
570         log.info("Validating NodeType({}) RequirementDefinition ({}) ", nodeTypeName, requirementDefinitionName)
571         val requirementNodeTypeName = requirementDefinition.node!!
572         val capabilityName = requirementDefinition.capability
573         val relationship = requirementDefinition.relationship!!
574
575         check(BluePrintTypes.validRelationShipDerivedFroms.contains(relationship)) {
576             throw BluePrintException(
577                 format(
578                     "Failed to get relationship({}) for NodeType({})'s requirement({}) ",
579                     relationship, nodeTypeName, requirementDefinitionName
580                 )
581             )
582         }
583
584         val relationShipNodeType = serviceTemplate.nodeTypes?.get(requirementNodeTypeName)
585             ?: throw BluePrintException(
586                 format(
587                     "Failed to get requirement NodeType({})'s for requirement({}) ",
588                     requirementNodeTypeName, requirementDefinitionName
589                 )
590             )
591
592         relationShipNodeType.capabilities?.get(capabilityName)
593             ?: throw BluePrintException(
594                 format(
595                     "Failed to get requirement NodeType({})'s capability({}) for NodeType ({})'s requirement({}) ",
596                     requirementNodeTypeName, capabilityName, nodeTypeName, requirementDefinitionName
597                 )
598             )
599     }
600
601     @Throws(BluePrintException::class)
602     open fun validateInterfaceDefinitions(interfaces: MutableMap<String, InterfaceDefinition>) {
603         paths.add("interfaces")
604         interfaces.forEach { interfaceName, interfaceDefinition ->
605             paths.add(interfaceName)
606             message.appendln("Validating : " + paths.joinToString(separator))
607             interfaceDefinition.operations?.let { validateOperationDefinitions(interfaceDefinition.operations!!) }
608             paths.removeAt(paths.lastIndex)
609         }
610         paths.removeAt(paths.lastIndex)
611     }
612
613     @Throws(BluePrintException::class)
614     open fun validateOperationDefinitions(operations: MutableMap<String, OperationDefinition>) {
615         paths.add("operations")
616         operations.forEach { opertaionName, operationDefinition ->
617             paths.add(opertaionName)
618             message.appendln("Validating : " + paths.joinToString(separator))
619             operationDefinition.implementation?.let { validateImplementation(operationDefinition.implementation!!) }
620             operationDefinition.inputs?.let { validatePropertyDefinitions(operationDefinition.inputs!!) }
621             operationDefinition.outputs?.let { validatePropertyDefinitions(operationDefinition.outputs!!) }
622             paths.removeAt(paths.lastIndex)
623         }
624         paths.removeAt(paths.lastIndex)
625     }
626
627     @Throws(BluePrintException::class)
628     open fun validateImplementation(implementation: Implementation) {
629         checkNotEmpty(implementation.primary) { "couldn't get implementation" }
630     }
631
632     @Throws(BluePrintException::class)
633     open fun checkValidArtifactType(artifactDefinitionName: String, artifactTypeName: String) {
634
635         val artifactType = serviceTemplate.artifactTypes?.get(artifactTypeName)
636             ?: throw BluePrintException("failed to artifactType($artifactTypeName) for ArtifactDefinition($artifactDefinitionName)")
637
638         checkValidArtifactTypeDerivedFrom(artifactTypeName, artifactType.derivedFrom)
639     }
640
641     @Throws(BluePrintException::class)
642     open fun checkValidArtifactTypeDerivedFrom(artifactTypeName: String, derivedFrom: String) {
643         check(BluePrintTypes.validArtifactTypeDerivedFroms.contains(derivedFrom)) {
644             throw BluePrintException("failed to get artifactType($artifactTypeName)'s derivedFrom($derivedFrom) definition")
645         }
646     }
647
648     @Throws(BluePrintException::class)
649     open fun checkValidDataTypeDerivedFrom(dataTypeName: String, derivedFrom: String) {
650         check(BluePrintTypes.validDataTypeDerivedFroms.contains(derivedFrom)) {
651             throw BluePrintException(format("Failed to get DataType({})'s  derivedFrom({}) definition ", dataTypeName, derivedFrom))
652         }
653     }
654
655     @Throws(BluePrintException::class)
656     open fun checkValidRelationshipTypeDerivedFrom(relationshipTypeName: String, derivedFrom: String) {
657         check(BluePrintTypes.validRelationShipDerivedFroms.contains(derivedFrom)) {
658             throw BluePrintException(format("Failed to get relationship type ({})'s  derivedFrom({}) definition ", relationshipTypeName, derivedFrom))
659         }
660     }
661
662     open fun checkPropertyValue(propertyName: String, propertyDefinition: PropertyDefinition, propertyAssignment: JsonNode) {
663         val propertyType = propertyDefinition.type
664         val isValid: Boolean
665
666         if (BluePrintTypes.validPrimitiveTypes().contains(propertyType)) {
667             isValid = JacksonUtils.checkJsonNodeValueOfPrimitiveType(propertyType, propertyAssignment)
668         } else if (BluePrintTypes.validCollectionTypes().contains(propertyType)) {
669
670             val entrySchemaType = propertyDefinition.entrySchema?.type
671                 ?: throw BluePrintException(format("Failed to get EntrySchema type for the collection property ({})", propertyName))
672
673             if (!BluePrintTypes.validPropertyTypes().contains(entrySchemaType)) {
674                 checkPropertyDataType(entrySchemaType, propertyName)
675             }
676             isValid = JacksonUtils.checkJsonNodeValueOfCollectionType(propertyType, propertyAssignment)
677         } else {
678             checkPropertyDataType(propertyType, propertyName)
679             isValid = true
680         }
681
682         check(isValid) {
683             throw BluePrintException(
684                 format(
685                     "property({}) defined of type({}) is not comptable with the value ({})",
686                     propertyName, propertyType, propertyAssignment
687                 )
688             )
689         }
690     }
691
692     private fun checkPropertyDataType(dataTypeName: String, propertyName: String) {
693
694         val dataType = serviceTemplate.dataTypes?.get(dataTypeName)
695             ?: throw BluePrintException(format("DataType ({}) for the property ({}) not found", dataTypeName, propertyName))
696
697         checkValidDataTypeDerivedFrom(propertyName, dataType.derivedFrom)
698     }
699
700     private fun checkPrimitiveOrComplex(dataType: String, propertyName: String): Boolean {
701         if (BluePrintTypes.validPrimitiveTypes().contains(dataType) || checkDataType(dataType)) {
702             return true
703         } else {
704             throw BluePrintException(format("DataType({}) for the property({}) is not valid", dataType, propertyName))
705         }
706     }
707
708     private fun checkDataType(key: String): Boolean {
709         return serviceTemplate.dataTypes?.containsKey(key) ?: false
710     }
711 }