e3a8f22215fd5e34d44204ec37fb2a2d87b01287
[ccsdk/cds.git] / ms / controllerblueprints / modules / service / src / main / kotlin / org / onap / ccsdk / apps / controllerblueprints / service / enhancer / BluePrintWorkflowEnhancerImpl.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.ccsdk.apps.controllerblueprints.service.enhancer
18
19 import com.att.eelf.configuration.EELFLogger
20 import com.att.eelf.configuration.EELFManager
21 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException
22 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintProcessorException
23 import org.onap.ccsdk.apps.controllerblueprints.core.ConfigModelConstant
24 import org.onap.ccsdk.apps.controllerblueprints.core.data.DataType
25 import org.onap.ccsdk.apps.controllerblueprints.core.data.PropertyDefinition
26 import org.onap.ccsdk.apps.controllerblueprints.core.data.Workflow
27 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintRepoService
28 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintTypeEnhancerService
29 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintWorkflowEnhancer
30 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintContext
31 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintRuntimeService
32 import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils
33 import org.onap.ccsdk.apps.controllerblueprints.resource.dict.ResourceAssignment
34 import org.springframework.beans.factory.config.ConfigurableBeanFactory
35 import org.springframework.context.annotation.Scope
36 import org.springframework.stereotype.Service
37
38 @Service
39 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
40 open class BluePrintWorkflowEnhancerImpl(private val bluePrintRepoService: BluePrintRepoService,
41                                          private val bluePrintTypeEnhancerService: BluePrintTypeEnhancerService,
42                                          private val resourceAssignmentEnhancerService: ResourceAssignmentEnhancerService)
43     : BluePrintWorkflowEnhancer {
44     private val log: EELFLogger = EELFManager.getInstance().getLogger(BluePrintNodeTemplateEnhancerImpl::class.toString())
45
46     lateinit var bluePrintRuntimeService: BluePrintRuntimeService<*>
47     lateinit var bluePrintContext: BluePrintContext
48
49     val PROPERTY_DEPENDENCY_NODE_TEMPLATES = "dependency-node-templates"
50
51
52     private val workflowDataTypes: MutableMap<String, DataType> = hashMapOf()
53
54     override fun enhance(bluePrintRuntimeService: BluePrintRuntimeService<*>, name: String, workflow: Workflow) {
55         log.info("Enhancing Workflow($name)")
56        this.bluePrintRuntimeService = bluePrintRuntimeService
57         this.bluePrintContext = bluePrintRuntimeService.bluePrintContext()
58
59         val dynamicPropertyName = "$name-properties"
60         if (workflow.inputs == null) {
61             workflow.inputs = hashMapOf()
62         }
63         // Clean Dynamic Property Field, If present
64         workflow.inputs?.remove(dynamicPropertyName)
65
66         // Enrich Only for Resource Assignment and Dynamic Input Properties if any
67         enhanceStepTargets(name, workflow)
68
69         // Enrich Workflow Inputs
70         enhanceWorkflowInputs(name, workflow)
71     }
72
73     open fun enhanceWorkflowInputs(name: String, workflow: Workflow) {
74
75         workflow.inputs?.let { inputs ->
76             bluePrintTypeEnhancerService.enhancePropertyDefinitions(bluePrintRuntimeService, inputs)
77         }
78     }
79
80     private fun enhanceStepTargets(name: String, workflow: Workflow) {
81
82         // Get the first Step Target NodeTemplate name( Since that is the DG Node Template)
83         val dgNodeTemplateName = bluePrintContext.workflowFirstStepNodeTemplate(name)
84
85         val dgNodeTemplate = bluePrintContext.nodeTemplateByName(dgNodeTemplateName)
86
87         // Get the Dependent Component Node Template Names
88         val dependencyNodeTemplateNodes = dgNodeTemplate.properties?.get(PROPERTY_DEPENDENCY_NODE_TEMPLATES)
89                 ?: throw BluePrintException("couldn't get property($PROPERTY_DEPENDENCY_NODE_TEMPLATES) ")
90
91         val dependencyNodeTemplates = JacksonUtils.getListFromJsonNode(dependencyNodeTemplateNodes, String::class.java)
92
93         log.info("workflow($name) dependent component NodeTemplates($dependencyNodeTemplates)")
94
95         // Check and Get Resource Assignment File
96         val resourceAssignmentArtifacts = dependencyNodeTemplates?.mapNotNull { componentNodeTemplateName ->
97             log.info("Identified workflow($name) targets($componentNodeTemplateName")
98             val resourceAssignmentArtifacts = bluePrintContext.nodeTemplateByName(componentNodeTemplateName)
99                     .artifacts?.filter {
100                 it.value.type == "artifact-mapping-resource"
101             }?.map {
102                 log.info("resource assignment artifacts(${it.key}) for NodeType(${componentNodeTemplateName})")
103                 it.value.file
104             }
105             resourceAssignmentArtifacts
106         }?.flatten()
107
108         log.info("Workflow($name) resource assignment files($resourceAssignmentArtifacts")
109
110         if (resourceAssignmentArtifacts != null && resourceAssignmentArtifacts.isNotEmpty()) {
111
112             // Add Workflow Dynamic Property
113             addWorkFlowDynamicPropertyDefinitions(name, workflow)
114
115             resourceAssignmentArtifacts.forEach { fileName ->
116
117                 val absoluteFilePath = "${bluePrintContext.rootPath}/$fileName"
118
119                 log.info("enriching workflow($name) artifacts file(${absoluteFilePath}")
120                 // Enhance Resource Assignment File
121                 val resourceAssignmentProperties = enhanceResourceAssignmentFile(absoluteFilePath)
122                 // Add Workflow Dynamic DataType
123                 addWorkFlowDynamicDataType(name, resourceAssignmentProperties)
124             }
125         }
126     }
127
128     private fun enhanceResourceAssignmentFile(filePath: String): MutableMap<String, PropertyDefinition> {
129
130         val resourceAssignmentProperties: MutableMap<String, PropertyDefinition> = hashMapOf()
131
132         val resourceAssignments: MutableList<ResourceAssignment> = JacksonUtils.getListFromFile(filePath, ResourceAssignment::class.java)
133                 as? MutableList<ResourceAssignment>
134                 ?: throw BluePrintProcessorException("couldn't get ResourceAssignment definitions for the file($filePath)")
135
136         // Call Resource Assignment Enhancer
137         resourceAssignmentEnhancerService.enhanceBluePrint(bluePrintTypeEnhancerService, bluePrintRuntimeService, resourceAssignments)
138
139         resourceAssignments.forEach { resourceAssignment ->
140             resourceAssignmentProperties[resourceAssignment.name] = resourceAssignment.property!!
141         }
142         return resourceAssignmentProperties
143     }
144
145     private fun addWorkFlowDynamicPropertyDefinitions(name: String, workflow: Workflow) {
146         val dynamicPropertyName = "$name-properties"
147         val propertyDefinition = PropertyDefinition()
148         propertyDefinition.description = "Dynamic PropertyDefinition for workflow($name)."
149         propertyDefinition.type = "dt-$dynamicPropertyName"
150         propertyDefinition.required = true
151         // Add to Workflow Inputs
152         workflow.inputs?.put(dynamicPropertyName, propertyDefinition)
153     }
154
155     private fun addWorkFlowDynamicDataType(workflowName: String, mappingProperties: MutableMap<String, PropertyDefinition>) {
156
157         val dataTypeName = "dt-$workflowName-properties"
158
159         var recipeDataType: DataType? = bluePrintContext.serviceTemplate.dataTypes?.get(dataTypeName)
160
161         if (recipeDataType == null) {
162             log.info("DataType not present for the recipe({})", dataTypeName)
163             recipeDataType = DataType()
164             recipeDataType.version = "1.0.0"
165             recipeDataType.description = "Dynamic DataType definition for workflow($workflowName)."
166             recipeDataType.derivedFrom = ConfigModelConstant.MODEL_TYPE_DATA_TYPE_DYNAMIC
167
168             val dataTypeProperties: MutableMap<String, PropertyDefinition> = hashMapOf()
169             recipeDataType.properties = dataTypeProperties
170
171             // Overwrite WorkFlow DataType
172             bluePrintContext.serviceTemplate.dataTypes?.put(dataTypeName, recipeDataType)
173
174         } else {
175             log.info("Dynamic dataType($dataTypeName) already present for workflow($workflowName).")
176         }
177         // Merge all the Recipe Properties
178         mappingProperties.forEach { propertyName, propertyDefinition ->
179             recipeDataType.properties?.put(propertyName, propertyDefinition)
180         }
181     }
182 }