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