Metadata for name, version, tags and type
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / blueprints / blueprint-core / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / core / utils / BluePrintMetadataUtils.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2018-2019 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.utils
19
20 import com.fasterxml.jackson.databind.JsonNode
21 import kotlinx.coroutines.runBlocking
22 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
23 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
24 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
25 import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
26 import org.onap.ccsdk.cds.controllerblueprints.core.data.ServiceTemplate
27 import org.onap.ccsdk.cds.controllerblueprints.core.data.ToscaMetaData
28 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintDefinitions
29 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
30 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
31 import org.onap.ccsdk.cds.controllerblueprints.core.readNBLines
32 import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintScriptsServiceImpl
33 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
34 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintImportService
35 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
36 import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBluePrintRuntimeService
37 import org.slf4j.LoggerFactory
38 import java.io.File
39 import java.util.Properties
40
41 class BluePrintMetadataUtils {
42     companion object {
43         private val log = LoggerFactory.getLogger(this::class.toString())
44
45         suspend fun toscaMetaData(basePath: String): ToscaMetaData {
46             val toscaMetaPath = basePath.plus(BluePrintConstants.PATH_DIVIDER)
47                 .plus(BluePrintConstants.TOSCA_METADATA_ENTRY_DEFINITION_FILE)
48             return toscaMetaDataFromMetaFile(toscaMetaPath)
49         }
50
51         suspend fun entryDefinitionFile(basePath: String): String {
52             val toscaMetaPath = basePath.plus(BluePrintConstants.PATH_DIVIDER)
53                 .plus(BluePrintConstants.TOSCA_METADATA_ENTRY_DEFINITION_FILE)
54             return toscaMetaDataFromMetaFile(toscaMetaPath).entityDefinitions
55         }
56
57         fun bluePrintEnvProperties(basePath: String): Properties {
58             val blueprintsEnvFilePath = basePath.plus(File.separator)
59                 .plus(BluePrintConstants.TOSCA_ENVIRONMENTS_DIR)
60             return environmentFileProperties(blueprintsEnvFilePath)
61         }
62
63         fun environmentFileProperties(pathName: String): Properties {
64             val properties = Properties()
65             val envDir = normalizedFile(pathName)
66             // Verify if the environment directory exists
67             if (envDir.exists() && envDir.isDirectory) {
68                 // Find all available environment files
69                 envDir.listFiles()!!
70                     .filter { it.name.endsWith(".properties") }
71                     .forEach {
72                         val istream = it.inputStream()
73                         properties.load(istream)
74                         istream.close()
75                     }
76             }
77             return properties
78         }
79
80         private suspend fun toscaMetaDataFromMetaFile(metaFilePath: String): ToscaMetaData {
81             val toscaMetaData = ToscaMetaData()
82             val lines = normalizedFile(metaFilePath).readNBLines()
83             lines.forEach { line ->
84                 if (line.contains(":")) {
85                     val keyValue = line.split(":")
86                     if (keyValue.size == 2) {
87                         val value: String = keyValue[1].trim()
88                         when (keyValue[0]) {
89                             "TOSCA-Meta-File-Version" -> toscaMetaData.toscaMetaFileVersion = value
90                             "CSAR-Version" -> toscaMetaData.csarVersion = value
91                             "Created-By" -> toscaMetaData.createdBy = value
92                             "Entry-Definitions" -> toscaMetaData.entityDefinitions = value
93                             "Template-Name" -> toscaMetaData.templateName = value
94                             "Template-Version" -> toscaMetaData.templateVersion = value
95                             "Template-Tags" -> toscaMetaData.templateTags = value
96                             "Template-Type" -> toscaMetaData.templateType = value
97                         }
98                     }
99                 }
100             }
101             return toscaMetaData
102         }
103
104         /** Get the default blueprint runtime for [id] and [blueprintBasePath] */
105         suspend fun getBluePrintRuntime(id: String, blueprintBasePath: String):
106             BluePrintRuntimeService<MutableMap<String, JsonNode>> {
107             val bluePrintContext: BluePrintContext = getBluePrintContext(blueprintBasePath)
108             return getBluePrintRuntime(id, bluePrintContext)
109         }
110
111         /** Get the default blocking blueprint runtime api for [id] and [blueprintBasePath] used in testing */
112         fun bluePrintRuntime(id: String, blueprintBasePath: String):
113             BluePrintRuntimeService<MutableMap<String, JsonNode>> = runBlocking {
114             val bluePrintContext: BluePrintContext = getBluePrintContext(blueprintBasePath)
115             getBluePrintRuntime(id, bluePrintContext)
116         }
117
118         /** Get the default blueprint runtime from [bluePrintContext] */
119         fun getBluePrintRuntime(id: String, bluePrintContext: BluePrintContext):
120             BluePrintRuntimeService<MutableMap<String, JsonNode>> {
121             checkNotEmpty(bluePrintContext.rootPath) { "blueprint context root path is missing." }
122             checkNotEmpty(bluePrintContext.entryDefinition) { "blueprint context entry definition is missing." }
123             val blueprintBasePath = bluePrintContext.rootPath
124             val bluePrintRuntimeService = DefaultBluePrintRuntimeService(id, bluePrintContext)
125             bluePrintRuntimeService.put(
126                 BluePrintConstants.PROPERTY_BLUEPRINT_BASE_PATH,
127                 blueprintBasePath.asJsonPrimitive()
128             )
129             bluePrintRuntimeService.put(BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID, id.asJsonPrimitive())
130             return bluePrintRuntimeService
131         }
132
133         /** Get the blueprint runtime for enhancement start for [id] and [blueprintBasePath] */
134         suspend fun getBaseEnhancementBluePrintRuntime(id: String, blueprintBasePath: String):
135             BluePrintRuntimeService<MutableMap<String, JsonNode>> {
136
137             val bluePrintContext: BluePrintContext = getBaseEnhancementBluePrintContext(blueprintBasePath)
138
139             val bluePrintRuntimeService = DefaultBluePrintRuntimeService(id, bluePrintContext)
140             bluePrintRuntimeService.put(
141                 BluePrintConstants.PROPERTY_BLUEPRINT_BASE_PATH,
142                 blueprintBasePath.asJsonPrimitive()
143             )
144             bluePrintRuntimeService.put(BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID, id.asJsonPrimitive())
145
146             return bluePrintRuntimeService
147         }
148
149         /** Get the default blueprint runtime for enhancement start for [id],  [blueprintBasePath] and [executionContext] */
150         suspend fun getBluePrintRuntime(
151             id: String,
152             blueprintBasePath: String,
153             executionContext: MutableMap<String, JsonNode>
154         ):
155             BluePrintRuntimeService<MutableMap<String, JsonNode>> {
156             val bluePrintContext: BluePrintContext = getBluePrintContext(blueprintBasePath)
157             val bluePrintRuntimeService = DefaultBluePrintRuntimeService(id, bluePrintContext)
158             executionContext.forEach {
159                 bluePrintRuntimeService.put(it.key, it.value)
160             }
161
162             bluePrintRuntimeService.setExecutionContext(executionContext)
163             return bluePrintRuntimeService
164         }
165
166         /** Get the default blueprint context for [blueprintBasePath]*/
167         suspend fun getBluePrintContext(blueprintBasePath: String): BluePrintContext {
168
169             val toscaMetaData: ToscaMetaData = toscaMetaData(blueprintBasePath)
170
171             log.info(
172                 "Reading blueprint type(${toscaMetaData.templateType}) path($blueprintBasePath) " +
173                     "and entry definition file (${toscaMetaData.entityDefinitions})"
174             )
175
176             // If the EntryDefinition is Kotlin file, compile and get Service Template
177             val bluePrintContext = when (toscaMetaData.templateType.toUpperCase()) {
178                 BluePrintConstants.BLUEPRINT_TYPE_KOTLIN_DSL -> readBlueprintKotlinFile(
179                     toscaMetaData,
180                     blueprintBasePath
181                 )
182                 BluePrintConstants.BLUEPRINT_TYPE_GENERIC_SCRIPT -> readBlueprintGenericScript(
183                     toscaMetaData,
184                     blueprintBasePath
185                 )
186                 BluePrintConstants.BLUEPRINT_TYPE_DEFAULT -> readBlueprintFile(
187                     toscaMetaData.entityDefinitions,
188                     blueprintBasePath
189                 )
190                 else ->
191                     throw BluePrintException(
192                         "Unknown blueprint type(${toscaMetaData.templateType}), " +
193                             "It should be any one of these types[${BluePrintConstants.BLUEPRINT_TYPE_KOTLIN_DSL}," +
194                             "${BluePrintConstants.BLUEPRINT_TYPE_GENERIC_SCRIPT}, " +
195                             "${BluePrintConstants.BLUEPRINT_TYPE_DEFAULT}]"
196                     )
197             }
198             // Copy the metadata info
199             copyMetaInfoToServiceTemplate(toscaMetaData, bluePrintContext.serviceTemplate)
200
201             return bluePrintContext
202         }
203
204         private suspend fun getBaseEnhancementBluePrintContext(blueprintBasePath: String): BluePrintContext {
205             val toscaMetaData: ToscaMetaData = toscaMetaData(blueprintBasePath)
206
207             // Clean Type files
208             BluePrintFileUtils.deleteBluePrintTypes(blueprintBasePath)
209             val rootFilePath: String = blueprintBasePath.plus(File.separator).plus(toscaMetaData.entityDefinitions)
210             val rootServiceTemplate = ServiceTemplateUtils.getServiceTemplate(rootFilePath)
211
212             // Copy the metadata info
213             copyMetaInfoToServiceTemplate(toscaMetaData, rootServiceTemplate)
214
215             // Clean the Import Definitions
216             BluePrintFileUtils.cleanImportTypes(rootServiceTemplate)
217
218             val blueprintContext = BluePrintContext(rootServiceTemplate)
219             blueprintContext.rootPath = blueprintBasePath
220             blueprintContext.entryDefinition = toscaMetaData.entityDefinitions
221             return blueprintContext
222         }
223
224         /** copy metadata defined in [toscaMetaData] to [serviceTemplate] */
225         private fun copyMetaInfoToServiceTemplate(toscaMetaData: ToscaMetaData, serviceTemplate: ServiceTemplate) {
226             if (serviceTemplate.metadata == null) serviceTemplate.metadata = mutableMapOf()
227             val metadata = serviceTemplate.metadata!!
228             metadata[BluePrintConstants.METADATA_TEMPLATE_AUTHOR] = toscaMetaData.createdBy
229             metadata[BluePrintConstants.METADATA_TEMPLATE_NAME] = toscaMetaData.templateName
230             metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION] = toscaMetaData.templateVersion
231             metadata[BluePrintConstants.METADATA_TEMPLATE_TAGS] = toscaMetaData.templateTags
232             metadata[BluePrintConstants.METADATA_TEMPLATE_TYPE] = toscaMetaData.templateType
233         }
234
235         private suspend fun readBlueprintFile(entityDefinitions: String, basePath: String): BluePrintContext {
236             val normalizedBasePath = normalizedPathName(basePath)
237             val rootFilePath = normalizedPathName(normalizedBasePath, entityDefinitions)
238             val rootServiceTemplate = ServiceTemplateUtils.getServiceTemplate(rootFilePath)
239
240             // Recursively Import Template files
241             val schemaImportResolverUtils = BluePrintImportService(rootServiceTemplate, normalizedBasePath)
242             val completeServiceTemplate = schemaImportResolverUtils.getImportResolvedServiceTemplate()
243             val blueprintContext = BluePrintContext(completeServiceTemplate)
244             blueprintContext.rootPath = normalizedBasePath
245             blueprintContext.entryDefinition = entityDefinitions
246             return blueprintContext
247         }
248
249         /** Reade the Service Template Definitions from the Kotlin file */
250         private suspend fun readBlueprintKotlinFile(toscaMetaData: ToscaMetaData, basePath: String): BluePrintContext {
251
252             val definitionClassName = toscaMetaData.entityDefinitions.removeSuffix(".kt")
253             val normalizedBasePath = normalizedPathName(basePath)
254
255             val bluePrintScriptsService = BluePrintScriptsServiceImpl()
256             val bluePrintDefinitions = bluePrintScriptsService
257                 .scriptInstance<BluePrintDefinitions>(
258                     normalizedBasePath, toscaMetaData.templateName,
259                     toscaMetaData.templateVersion, definitionClassName, false
260                 )
261             // Get the Service Template
262             val serviceTemplate = bluePrintDefinitions.serviceTemplate()
263
264             // Clean the Default type import Definitions
265             BluePrintFileUtils.cleanImportTypes(serviceTemplate)
266
267             val blueprintContext = BluePrintContext(serviceTemplate)
268             blueprintContext.rootPath = normalizedBasePath
269             blueprintContext.entryDefinition = toscaMetaData.entityDefinitions
270             blueprintContext.otherDefinitions = bluePrintDefinitions.otherDefinitions()
271             return blueprintContext
272         }
273
274         /** Reade the Service Template Definitions from the generic script types */
275         private fun readBlueprintGenericScript(toscaMetaData: ToscaMetaData, basePath: String): BluePrintContext {
276             return BluePrintContext(ServiceTemplate())
277         }
278     }
279 }