Merge "Migrate ccsdk-cds docs"
[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({}) ", nodeTemplateName, capabilityName, nodeTemplate.type
335                     )
336                 )
337
338             validateCapabilityAssignment(nodeTemplateName, capabilityName, capabilityDefinition, capabilityAssignment)
339
340             paths.removeAt(paths.lastIndex)
341         }
342         paths.removeAt(paths.lastIndex)
343     }
344
345     @Throws(BluePrintException::class)
346     open fun validateCapabilityAssignment(
347         nodeTemplateName: String,
348         capabilityName: String,
349         capabilityDefinition: CapabilityDefinition,
350         capabilityAssignment: CapabilityAssignment
351     ) {
352
353         capabilityAssignment.properties?.let { validatePropertyAssignments(capabilityDefinition.properties!!, capabilityAssignment.properties!!) }
354     }
355
356     @Throws(BluePrintException::class)
357     open fun validateRequirementAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
358         val requirements = nodeTemplate.requirements
359         paths.add("requirements")
360         requirements?.forEach { requirementName, requirementAssignment ->
361             paths.add(requirementName)
362             val requirementDefinition = nodeType.requirements?.get(requirementName)
363                 ?: throw BluePrintException(
364                     format(
365                         "Failed to get NodeTemplate({}) requirement definition ({}) from" +
366                                 " NodeType({}) ", nodeTemplateName, requirementName, nodeTemplate.type
367                     )
368                 )
369             // Validate Requirement Assignment
370             validateRequirementAssignment(nodeTemplateName, requirementName, requirementDefinition, requirementAssignment)
371             paths.removeAt(paths.lastIndex)
372         }
373         paths.removeAt(paths.lastIndex)
374     }
375
376     @Throws(BluePrintException::class)
377     open fun validateRequirementAssignment(
378         nodeTemplateName: String,
379         requirementAssignmentName: String,
380         requirementDefinition: RequirementDefinition,
381         requirementAssignment: RequirementAssignment
382     ) {
383         log.info("Validating NodeTemplate({}) requirement assignment ({}) ", nodeTemplateName, requirementAssignmentName)
384         val requirementNodeTemplateName = requirementAssignment.node!!
385         val capabilityName = requirementAssignment.capability
386         val relationship = requirementAssignment.relationship!!
387
388         check(BluePrintTypes.validRelationShipDerivedFroms.contains(relationship)) {
389             throw BluePrintException(
390                 format(
391                     "Failed to get relationship type ({}) for NodeTemplate({})'s requirement({}) ",
392                     relationship, nodeTemplateName, requirementAssignmentName
393                 )
394             )
395         }
396
397         val relationShipNodeTemplate = serviceTemplate.topologyTemplate?.nodeTemplates?.get(requirementNodeTemplateName)
398             ?: throw BluePrintException(
399                 format(
400                     "Failed to get requirement NodeTemplate({})'s for NodeTemplate({}) requirement({}) ",
401                     requirementNodeTemplateName, nodeTemplateName, requirementAssignmentName
402                 )
403             )
404
405         relationShipNodeTemplate.capabilities?.get(capabilityName)
406             ?: throw BluePrintException(
407                 format(
408                     "Failed to get requirement NodeTemplate({})'s capability({}) for NodeTemplate ({})'s requirement({}) ",
409                     requirementNodeTemplateName, capabilityName, nodeTemplateName, requirementAssignmentName
410                 )
411             )
412     }
413
414     @Throws(BluePrintException::class)
415     open fun validateInterfaceAssignments(nodeType: NodeType, nodeTemplateName: String, nodeTemplate: NodeTemplate) {
416
417         val interfaces = nodeTemplate.interfaces
418         paths.add("interfaces")
419         interfaces?.forEach { interfaceAssignmentName, interfaceAssignment ->
420             paths.add(interfaceAssignmentName)
421             val interfaceDefinition = nodeType.interfaces?.get(interfaceAssignmentName)
422                 ?: throw BluePrintException(
423                     format(
424                         "Failed to get NodeTemplate({}) interface definition ({}) from" +
425                                 " NodeType({}) ", nodeTemplateName, interfaceAssignmentName, nodeTemplate.type
426                     )
427                 )
428
429             validateInterfaceAssignment(
430                 nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
431                 interfaceAssignment
432             )
433             paths.removeAt(paths.lastIndex)
434         }
435         paths.removeAt(paths.lastIndex)
436     }
437
438     @Throws(BluePrintException::class)
439     open fun validateInterfaceAssignment(
440         nodeTemplateName: String,
441         interfaceAssignmentName: String,
442         interfaceDefinition: InterfaceDefinition,
443         interfaceAssignment: InterfaceAssignment
444     ) {
445
446         val operations = interfaceAssignment.operations
447         operations?.let {
448             validateInterfaceOperationsAssignment(
449                 nodeTemplateName, interfaceAssignmentName, interfaceDefinition,
450                 interfaceAssignment
451             )
452         }
453     }
454
455     @Throws(BluePrintException::class)
456     open fun validateInterfaceOperationsAssignment(
457         nodeTemplateName: String,
458         interfaceAssignmentName: String,
459         interfaceDefinition: InterfaceDefinition,
460         interfaceAssignment: InterfaceAssignment
461     ) {
462
463         val operations = interfaceAssignment.operations
464         operations?.let {
465             it.forEach { operationAssignmentName, operationAssignments ->
466
467                 val operationDefinition = interfaceDefinition.operations?.get(operationAssignmentName)
468                     ?: throw BluePrintException(
469                         format(
470                             "Failed to get NodeTemplate({}) operation definition ({}) ",
471                             nodeTemplateName, operationAssignmentName
472                         )
473                     )
474
475                 log.info(
476                     "Validation NodeTemplate({}) Interface({}) Operation ({})", nodeTemplateName,
477                     interfaceAssignmentName, operationAssignmentName
478                 )
479
480                 val inputs = operationAssignments.inputs
481                 val outputs = operationAssignments.outputs
482
483                 inputs?.forEach { propertyName, propertyAssignment ->
484                     val propertyDefinition = operationDefinition.inputs?.get(propertyName)
485                         ?: throw BluePrintException(
486                             format(
487                                 "Failed to get NodeTemplate({}) operation definition ({}) " +
488                                         "property definition({})", nodeTemplateName, operationAssignmentName, propertyName
489                             )
490                         )
491                     // Check the property values with property definition
492                     validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
493                 }
494
495                 outputs?.forEach { propertyName, propertyAssignment ->
496                     val propertyDefinition = operationDefinition.outputs?.get(propertyName)
497                         ?: throw BluePrintException(
498                             format(
499                                 "Failed to get NodeTemplate({}) operation definition ({}) " +
500                                         "output property definition({})", nodeTemplateName, operationAssignmentName,
501                                 propertyName
502                             )
503                         )
504                     // Check the property values with property definition
505                     validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
506                 }
507             }
508         }
509     }
510
511     @Throws(BluePrintException::class)
512     open fun validateCapabilityDefinitions(nodeTypeName: String, nodeType: NodeType) {
513         val capabilities = nodeType.capabilities
514         paths.add("capabilities")
515         capabilities?.forEach { capabilityName, capabilityDefinition ->
516             paths.add(capabilityName)
517
518             validateCapabilityDefinition(nodeTypeName, nodeType, capabilityName, capabilityDefinition)
519
520             paths.removeAt(paths.lastIndex)
521         }
522         paths.removeAt(paths.lastIndex)
523     }
524
525     @Throws(BluePrintException::class)
526     open fun validateCapabilityDefinition(
527         nodeTypeName: String,
528         nodeType: NodeType,
529         capabilityName: String,
530         capabilityDefinition: CapabilityDefinition
531     ) {
532         val capabilityType = capabilityDefinition.type
533         check(BluePrintTypes.validCapabilityTypes.contains(capabilityType)) {
534             throw BluePrintException(
535                 format(
536                     "Failed to get CapabilityType({}) for NodeType({})",
537                     capabilityType, nodeTypeName
538                 )
539             )
540         }
541     }
542
543     @Throws(BluePrintException::class)
544     open fun validateRequirementDefinitions(nodeName: String, nodeType: NodeType) {
545         paths.add("requirements")
546         val requirements = nodeType.requirements
547
548         requirements?.forEach { requirementDefinitionName, requirementDefinition ->
549             paths.add(requirementDefinitionName)
550             message.appendln("Validating : " + paths.joinToString(separator))
551             validateRequirementDefinition(nodeName, nodeType, requirementDefinitionName, requirementDefinition)
552             paths.removeAt(paths.lastIndex)
553         }
554         paths.removeAt(paths.lastIndex)
555     }
556
557     @Throws(BluePrintException::class)
558     open fun validateRequirementDefinition(
559         nodeTypeName: String,
560         nodeType: NodeType,
561         requirementDefinitionName: String,
562         requirementDefinition: RequirementDefinition
563     ) {
564
565         log.info("Validating NodeType({}) RequirementDefinition ({}) ", nodeTypeName, requirementDefinitionName)
566         val requirementNodeTypeName = requirementDefinition.node!!
567         val capabilityName = requirementDefinition.capability
568         val relationship = requirementDefinition.relationship!!
569
570         check(BluePrintTypes.validRelationShipDerivedFroms.contains(relationship)) {
571             throw BluePrintException(
572                 format(
573                     "Failed to get relationship({}) for NodeType({})'s requirement({}) ",
574                     relationship, nodeTypeName, requirementDefinitionName
575                 )
576             )
577         }
578
579         val relationShipNodeType = serviceTemplate.nodeTypes?.get(requirementNodeTypeName)
580             ?: throw BluePrintException(
581                 format(
582                     "Failed to get requirement NodeType({})'s for requirement({}) ",
583                     requirementNodeTypeName, requirementDefinitionName
584                 )
585             )
586
587         relationShipNodeType.capabilities?.get(capabilityName)
588             ?: throw BluePrintException(
589                 format(
590                     "Failed to get requirement NodeType({})'s capability({}) for NodeType ({})'s requirement({}) ",
591                     requirementNodeTypeName, capabilityName, nodeTypeName, requirementDefinitionName
592                 )
593             )
594     }
595
596     @Throws(BluePrintException::class)
597     open fun validateInterfaceDefinitions(interfaces: MutableMap<String, InterfaceDefinition>) {
598         paths.add("interfaces")
599         interfaces.forEach { interfaceName, interfaceDefinition ->
600             paths.add(interfaceName)
601             message.appendln("Validating : " + paths.joinToString(separator))
602             interfaceDefinition.operations?.let { validateOperationDefinitions(interfaceDefinition.operations!!) }
603             paths.removeAt(paths.lastIndex)
604         }
605         paths.removeAt(paths.lastIndex)
606     }
607
608     @Throws(BluePrintException::class)
609     open fun validateOperationDefinitions(operations: MutableMap<String, OperationDefinition>) {
610         paths.add("operations")
611         operations.forEach { opertaionName, operationDefinition ->
612             paths.add(opertaionName)
613             message.appendln("Validating : " + paths.joinToString(separator))
614             operationDefinition.implementation?.let { validateImplementation(operationDefinition.implementation!!) }
615             operationDefinition.inputs?.let { validatePropertyDefinitions(operationDefinition.inputs!!) }
616             operationDefinition.outputs?.let { validatePropertyDefinitions(operationDefinition.outputs!!) }
617             paths.removeAt(paths.lastIndex)
618         }
619         paths.removeAt(paths.lastIndex)
620     }
621
622     @Throws(BluePrintException::class)
623     open fun validateImplementation(implementation: Implementation) {
624         checkNotEmpty(implementation.primary) { "couldn't get implementation" }
625     }
626
627     @Throws(BluePrintException::class)
628     open fun checkValidArtifactType(artifactDefinitionName: String, artifactTypeName: String) {
629
630         val artifactType = serviceTemplate.artifactTypes?.get(artifactTypeName)
631             ?: throw BluePrintException("failed to artifactType($artifactTypeName) for ArtifactDefinition($artifactDefinitionName)")
632
633         checkValidArtifactTypeDerivedFrom(artifactTypeName, artifactType.derivedFrom)
634     }
635
636     @Throws(BluePrintException::class)
637     open fun checkValidArtifactTypeDerivedFrom(artifactTypeName: String, derivedFrom: String) {
638         check(BluePrintTypes.validArtifactTypeDerivedFroms.contains(derivedFrom)) {
639             throw BluePrintException("failed to get artifactType($artifactTypeName)'s derivedFrom($derivedFrom) definition")
640         }
641     }
642
643     @Throws(BluePrintException::class)
644     open fun checkValidDataTypeDerivedFrom(dataTypeName: String, derivedFrom: String) {
645         check(BluePrintTypes.validDataTypeDerivedFroms.contains(derivedFrom)) {
646             throw BluePrintException(format("Failed to get DataType({})'s  derivedFrom({}) definition ", dataTypeName, derivedFrom))
647         }
648     }
649
650     @Throws(BluePrintException::class)
651     open fun checkValidRelationshipTypeDerivedFrom(relationshipTypeName: String, derivedFrom: String) {
652         check(BluePrintTypes.validRelationShipDerivedFroms.contains(derivedFrom)) {
653             throw BluePrintException(format("Failed to get relationship type ({})'s  derivedFrom({}) definition ", relationshipTypeName, derivedFrom))
654         }
655     }
656
657     open fun checkPropertyValue(propertyName: String, propertyDefinition: PropertyDefinition, propertyAssignment: JsonNode) {
658         val propertyType = propertyDefinition.type
659         val isValid: Boolean
660
661         if (BluePrintTypes.validPrimitiveTypes().contains(propertyType)) {
662             isValid = JacksonUtils.checkJsonNodeValueOfPrimitiveType(propertyType, propertyAssignment)
663         } else if (BluePrintTypes.validCollectionTypes().contains(propertyType)) {
664
665             val entrySchemaType = propertyDefinition.entrySchema?.type
666                 ?: throw BluePrintException(format("Failed to get EntrySchema type for the collection property ({})", propertyName))
667
668             if (!BluePrintTypes.validPropertyTypes().contains(entrySchemaType)) {
669                 checkPropertyDataType(entrySchemaType, propertyName)
670             }
671             isValid = JacksonUtils.checkJsonNodeValueOfCollectionType(propertyType, propertyAssignment)
672         } else {
673             checkPropertyDataType(propertyType, propertyName)
674             isValid = true
675         }
676
677         check(isValid) {
678             throw BluePrintException(
679                 format(
680                     "property({}) defined of type({}) is not comptable with the value ({})",
681                     propertyName, propertyType, propertyAssignment
682                 )
683             )
684         }
685     }
686
687     private fun checkPropertyDataType(dataTypeName: String, propertyName: String) {
688
689         val dataType = serviceTemplate.dataTypes?.get(dataTypeName)
690             ?: throw BluePrintException(format("DataType ({}) for the property ({}) not found", dataTypeName, propertyName))
691
692         checkValidDataTypeDerivedFrom(propertyName, dataType.derivedFrom)
693     }
694
695     private fun checkPrimitiveOrComplex(dataType: String, propertyName: String): Boolean {
696         if (BluePrintTypes.validPrimitiveTypes().contains(dataType) || checkDataType(dataType)) {
697             return true
698         } else {
699             throw BluePrintException(format("DataType({}) for the property({}) is not valid", dataType, propertyName))
700         }
701     }
702
703     private fun checkDataType(key: String): Boolean {
704         return serviceTemplate.dataTypes?.containsKey(key) ?: false
705     }
706 }