Improve service template access through cache.
[ccsdk/cds.git] / ms / controllerblueprints / modules / blueprint-core / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / core / utils / BluePrintFileUtils.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2019 Bell Canada.
4  * Modifications Copyright © 2019 IBM.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 package org.onap.ccsdk.cds.controllerblueprints.core.utils
20
21 import kotlinx.coroutines.runBlocking
22 import org.apache.commons.io.FileUtils
23 import org.apache.commons.lang3.StringUtils
24 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
25 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
26 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
27 import org.onap.ccsdk.cds.controllerblueprints.core.data.ImportDefinition
28 import org.onap.ccsdk.cds.controllerblueprints.core.data.ServiceTemplate
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.service.BluePrintContext
32 import org.slf4j.LoggerFactory
33 import java.io.File
34 import java.io.FileFilter
35 import java.nio.file.Files
36 import java.nio.file.Path
37 import java.nio.file.Paths
38 import java.nio.file.StandardOpenOption
39
40
41 class BluePrintFileUtils {
42     companion object {
43
44         private val log = LoggerFactory.getLogger(this::class.toString())
45
46         fun createEmptyBluePrint(basePath: String) {
47
48             val blueprintDir = File(basePath)
49             FileUtils.deleteDirectory(blueprintDir)
50
51             Files.createDirectories(blueprintDir.toPath())
52
53             val metaDataDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_METADATA_DIR))
54             Files.createDirectories(metaDataDir.toPath())
55
56             val metaFile = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants
57                     .TOSCA_METADATA_ENTRY_DEFINITION_FILE))
58             Files.write(metaFile.toPath(), getMetaDataContent().toByteArray(), StandardOpenOption.CREATE_NEW)
59
60             val definitionsDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR))
61             Files.createDirectories(definitionsDir.toPath())
62
63             val scriptsDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_SCRIPTS_DIR))
64             Files.createDirectories(scriptsDir.toPath())
65
66             val plansDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_PLANS_DIR))
67             Files.createDirectories(plansDir.toPath())
68
69             val templatesDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_TEMPLATES_DIR))
70             Files.createDirectories(templatesDir.toPath())
71
72         }
73
74         fun copyBluePrint(sourcePath: String, targetPath: String) {
75             val sourceFile = File(sourcePath)
76             val targetFile = File(targetPath)
77             sourceFile.copyRecursively(targetFile, true)
78         }
79
80         fun deleteBluePrintTypes(basePath: String) {
81             val definitionPath = basePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR)
82             log.info("deleting definition types under : $definitionPath")
83
84             val definitionDir = File(definitionPath)
85             // Find the Type Definitions
86             val fileFilter = FileFilter { pathname -> pathname.absolutePath.endsWith("_types.json") }
87             // Delete the Type Files
88             definitionDir.listFiles(fileFilter).forEach {
89                 Files.deleteIfExists(it.toPath())
90             }
91         }
92
93         fun writeEnhancedBluePrint(blueprintContext: BluePrintContext) {
94
95             // Write Blueprint Types
96             writeBluePrintTypes(blueprintContext)
97             // Re Populate the Imports
98             populateDefaultImports(blueprintContext)
99             // Rewrite the Entry Definition Files
100             writeEntryDefinitionFile(blueprintContext)
101
102         }
103
104         fun writeBluePrintTypes(blueprintContext: BluePrintContext) {
105
106             val basePath = blueprintContext.rootPath
107             val definitionPath = basePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR)
108             val definitionDir = File(definitionPath)
109
110             check(definitionDir.exists()) {
111                 throw BluePrintException(ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get definition file under " +
112                         "path(${definitionDir.absolutePath})")
113             }
114
115             blueprintContext.serviceTemplate.dataTypes?.let {
116                 val dataTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_DATA_TYPES, it.toSortedMap(), true)
117                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_DATA_TYPES, dataTypesContent)
118             }
119
120             blueprintContext.serviceTemplate.relationshipTypes?.let {
121                 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_RELATIONSHIP_TYPES, it.toSortedMap(), true)
122                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_RELATIONSHIP_TYPES, nodeTypesContent)
123             }
124
125             blueprintContext.serviceTemplate.artifactTypes?.let {
126                 val artifactTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_ARTIFACT_TYPES, it.toSortedMap(), true)
127                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_ARTIFACT_TYPES, artifactTypesContent)
128             }
129
130             blueprintContext.serviceTemplate.nodeTypes?.let {
131                 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_NODE_TYPES, it.toSortedMap(), true)
132                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_NODE_TYPES, nodeTypesContent)
133             }
134
135             blueprintContext.serviceTemplate.policyTypes?.let {
136                 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_POLICY_TYPES, it.toSortedMap(), true)
137                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_POLICY_TYPES, nodeTypesContent)
138             }
139         }
140
141         private fun populateDefaultImports(blueprintContext: BluePrintContext) {
142             // Get the Default Types
143             val types = arrayListOf(BluePrintConstants.PATH_DATA_TYPES, BluePrintConstants.PATH_RELATIONSHIP_TYPES,
144                     BluePrintConstants.PATH_ARTIFACT_TYPES, BluePrintConstants.PATH_NODE_TYPES,
145                     BluePrintConstants.PATH_POLICY_TYPES)
146
147             // Clean Type Imports
148             cleanImportTypes(blueprintContext.serviceTemplate)
149
150             val imports = mutableListOf<ImportDefinition>()
151             types.forEach { typeName ->
152                 val import = ImportDefinition()
153                 import.file = BluePrintConstants.TOSCA_DEFINITIONS_DIR.plus("/$typeName.json")
154                 imports.add(import)
155             }
156
157             blueprintContext.serviceTemplate.imports = imports
158         }
159
160         fun cleanImportTypes(serviceTemplate: ServiceTemplate) {
161             // Clean the Type imports
162             val toDeleteTypes = serviceTemplate.imports?.filter {
163                 it.file.endsWith("_types.json")
164             }
165
166             if (toDeleteTypes != null && toDeleteTypes.isNotEmpty()) {
167                 serviceTemplate.imports?.removeAll(toDeleteTypes)
168             }
169         }
170
171         /**
172          * Re Generate the Blueprint Service Template Definition file based on BluePrint Context.
173          */
174         private fun writeEntryDefinitionFile(blueprintContext: BluePrintContext) {
175
176             val absoluteEntryDefinitionFile = blueprintContext.rootPath.plus(File.separator).plus(blueprintContext.entryDefinition)
177
178             val serviceTemplate = blueprintContext.serviceTemplate
179
180             // Clone the Service Template
181             val writeServiceTemplate = serviceTemplate.clone()
182             writeServiceTemplate.dataTypes = null
183             writeServiceTemplate.artifactTypes = null
184             writeServiceTemplate.policyTypes = null
185             writeServiceTemplate.relationshipTypes = null
186             writeServiceTemplate.nodeTypes = null
187
188             // Write the Service Template
189             writeDefinitionFile(absoluteEntryDefinitionFile, JacksonUtils.getJson(writeServiceTemplate, true))
190         }
191
192         fun writeDefinitionFile(definitionFileName: String, content: String) = runBlocking {
193             val definitionFile = File(definitionFileName)
194             // Delete the File If exists
195             Files.deleteIfExists(definitionFile.toPath())
196
197             Files.write(definitionFile.toPath(), content.toByteArray(), StandardOpenOption.CREATE_NEW)
198             check(definitionFile.exists()) {
199                 throw BluePrintException(ErrorCode.BLUEPRINT_WRITING_FAIL.value, "couldn't write definition file under " +
200                         "path(${definitionFile.absolutePath})")
201             }
202         }
203
204         private fun writeTypeFile(definitionPath: String, type: String, content: String) = runBlocking {
205             val typeFile = File(definitionPath.plus(File.separator).plus("$type.json"))
206
207             Files.write(typeFile.toPath(), content.toByteArray(), StandardOpenOption.CREATE_NEW)
208             check(typeFile.exists()) {
209                 throw BluePrintException(ErrorCode.BLUEPRINT_WRITING_FAIL.value, "couldn't write $type.json file under " +
210                         "path(${typeFile.absolutePath})")
211             }
212         }
213
214         private fun getMetaDataContent(): String {
215             return "TOSCA-Meta-File-Version: 1.0.0" +
216                     "\nCSAR-Version: <VERSION>" +
217                     "\nCreated-By: <AUTHOR NAME>" +
218                     "\nEntry-Definitions: Definitions/<BLUEPRINT_NAME>.json" +
219                     "\nTemplate-Name: <BLUEPRINT_NAME>"+
220                     "\nTemplate-Tags: <BLUEPRINT_VERSION>"+
221                     "\nTemplate-Tags: <TAGS>"
222         }
223
224
225         fun getBluePrintFile(fileName: String, targetPath: Path): File {
226             val filePath = targetPath.resolve(fileName).toString()
227             val file = File(filePath)
228             check(file.exists()) {
229                 throw BluePrintException(ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get definition file under " +
230                         "path(${file.absolutePath})")
231             }
232             return file
233         }
234
235         fun getCbaStorageDirectory(path: String): Path {
236             check(StringUtils.isNotBlank(path)) {
237                 throw BluePrintException(ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get " +
238                         "Blueprint folder under path($path)")
239             }
240
241             val fileStorageLocation = Paths.get(path).toAbsolutePath().normalize()
242
243             if (!Files.exists(fileStorageLocation))
244                 Files.createDirectories(fileStorageLocation)
245
246             return fileStorageLocation
247         }
248
249         fun compileCacheKey(basePath: String): String {
250             return normalizedPathName(basePath)
251         }
252
253         private fun compileJarFileName(artifactName: String, artifactVersion: String): String {
254             return "$artifactName-$artifactVersion-cba-kts.jar"
255         }
256
257         fun compileJarFilePathName(basePath: String, artifactName: String, artifactVersion: String): String {
258             return normalizedPathName(basePath, BluePrintConstants.TOSCA_SCRIPTS_KOTLIN_DIR,
259                     compileJarFileName(artifactName, artifactVersion))
260         }
261
262         fun compileJarFile(basePath: String, artifactName: String, artifactVersion: String): File {
263             return normalizedFile(compileJarFilePathName(basePath,
264                     artifactName, artifactVersion))
265         }
266
267         fun stripFileExtension(fileName: String): String {
268             val dotIndexe = fileName.lastIndexOf('.')
269
270             // In case dot is in first position, we are dealing with a hidden file rather than an extension
271             return if (dotIndexe > 0) fileName.substring(0, dotIndexe) else fileName
272         }
273
274     }
275 }