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