5f9725f10fc1667667e5c18877bace1d88e40842
[ccsdk/cds.git] /
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2019 Bell Canada.
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 org.slf4j.LoggerFactory
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.service.BluePrintContext
30 import java.io.File
31 import java.io.FileFilter
32 import java.nio.file.Files
33 import java.nio.file.Path
34 import java.nio.file.Paths
35 import java.nio.file.StandardOpenOption
36
37
38 class BluePrintFileUtils {
39     companion object {
40
41         private val log= LoggerFactory.getLogger(this::class.toString())
42
43         fun createEmptyBluePrint(basePath: String) {
44
45             val blueprintDir = File(basePath)
46             FileUtils.deleteDirectory(blueprintDir)
47
48             Files.createDirectories(blueprintDir.toPath())
49
50             val metaDataDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_METADATA_DIR))
51             Files.createDirectories(metaDataDir.toPath())
52
53             val metaFile = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants
54                     .TOSCA_METADATA_ENTRY_DEFINITION_FILE))
55             Files.write(metaFile.toPath(), getMetaDataContent().toByteArray(), StandardOpenOption.CREATE_NEW)
56
57             val definitionsDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR))
58             Files.createDirectories(definitionsDir.toPath())
59
60             val scriptsDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_SCRIPTS_DIR))
61             Files.createDirectories(scriptsDir.toPath())
62
63             val plansDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_PLANS_DIR))
64             Files.createDirectories(plansDir.toPath())
65
66             val templatesDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_TEMPLATES_DIR))
67             Files.createDirectories(templatesDir.toPath())
68
69         }
70
71         fun copyBluePrint(sourcePath: String, targetPath: String) {
72             val sourceFile = File(sourcePath)
73             val targetFile = File(targetPath)
74             sourceFile.copyRecursively(targetFile, true)
75         }
76
77         fun deleteBluePrintTypes(basePath: String) {
78             val definitionPath = basePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR)
79             log.info("deleting definition types under : $definitionPath")
80
81             val definitionDir = File(definitionPath)
82             // Find the Type Definitions
83             val fileFilter = FileFilter { pathname -> pathname.absolutePath.endsWith("_types.json") }
84             // Delete the Type Files
85             definitionDir.listFiles(fileFilter).forEach {
86                 Files.deleteIfExists(it.toPath())
87             }
88         }
89
90         fun writeEnhancedBluePrint(blueprintContext: BluePrintContext) {
91
92             // Write Blueprint Types
93             writeBluePrintTypes(blueprintContext)
94             // Re Populate the Imports
95             populateDefaultImports(blueprintContext)
96             // Rewrite the Entry Definition Files
97             writeEntryDefinitionFile(blueprintContext)
98
99         }
100
101         fun writeBluePrintTypes(blueprintContext: BluePrintContext) {
102
103             val basePath = blueprintContext.rootPath
104             val definitionPath = basePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR)
105             val definitionDir = File(definitionPath)
106
107             check(definitionDir.exists()) {
108                 throw BluePrintException(ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get definition file under " +
109                         "path(${definitionDir.absolutePath})")
110             }
111
112             blueprintContext.serviceTemplate.dataTypes?.let {
113                 val dataTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_DATA_TYPES, it.toSortedMap(), true)
114                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_DATA_TYPES, dataTypesContent)
115             }
116
117             blueprintContext.serviceTemplate.relationshipTypes?.let {
118                 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_RELATIONSHIP_TYPES, it.toSortedMap(), true)
119                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_RELATIONSHIP_TYPES, nodeTypesContent)
120             }
121
122             blueprintContext.serviceTemplate.artifactTypes?.let {
123                 val artifactTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_ARTIFACT_TYPES, it.toSortedMap(), true)
124                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_ARTIFACT_TYPES, artifactTypesContent)
125             }
126
127             blueprintContext.serviceTemplate.nodeTypes?.let {
128                 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_NODE_TYPES, it.toSortedMap(), true)
129                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_NODE_TYPES, nodeTypesContent)
130             }
131
132             blueprintContext.serviceTemplate.policyTypes?.let {
133                 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_POLICY_TYPES, it.toSortedMap(), true)
134                 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_POLICY_TYPES, nodeTypesContent)
135             }
136         }
137
138         private fun populateDefaultImports(blueprintContext: BluePrintContext) {
139             // Get the Default Types
140             val types = arrayListOf(BluePrintConstants.PATH_DATA_TYPES, BluePrintConstants.PATH_RELATIONSHIP_TYPES,
141                     BluePrintConstants.PATH_ARTIFACT_TYPES, BluePrintConstants.PATH_NODE_TYPES,
142                     BluePrintConstants.PATH_POLICY_TYPES)
143
144             // Clean Type Imports
145             cleanImportTypes(blueprintContext.serviceTemplate)
146
147             val imports = mutableListOf<ImportDefinition>()
148             types.forEach { typeName ->
149                 val import = ImportDefinition()
150                 import.file = BluePrintConstants.TOSCA_DEFINITIONS_DIR.plus("/$typeName.json")
151                 imports.add(import)
152             }
153
154             blueprintContext.serviceTemplate.imports = imports
155         }
156
157         fun cleanImportTypes(serviceTemplate: ServiceTemplate) {
158             // Clean the Type imports
159             val toDeleteTypes = serviceTemplate.imports?.filter {
160                 it.file.endsWith("_types.json")
161             }
162
163             if (toDeleteTypes != null && toDeleteTypes.isNotEmpty()) {
164                 serviceTemplate.imports?.removeAll(toDeleteTypes)
165             }
166         }
167
168         /**
169          * Re Generate the Blueprint Service Template Definition file based on BluePrint Context.
170          */
171         private fun writeEntryDefinitionFile(blueprintContext: BluePrintContext) {
172
173             val absoluteEntryDefinitionFile = blueprintContext.rootPath.plus(File.separator).plus(blueprintContext.entryDefinition)
174
175             val serviceTemplate = blueprintContext.serviceTemplate
176
177             // Clone the Service Template
178             val writeServiceTemplate = serviceTemplate.clone()
179             writeServiceTemplate.dataTypes = null
180             writeServiceTemplate.artifactTypes = null
181             writeServiceTemplate.policyTypes = null
182             writeServiceTemplate.relationshipTypes = null
183             writeServiceTemplate.nodeTypes = null
184
185             // Write the Service Template
186             writeDefinitionFile(absoluteEntryDefinitionFile, JacksonUtils.getJson(writeServiceTemplate, true))
187         }
188
189         fun writeDefinitionFile(definitionFileName: String, content: String) = runBlocking {
190             val definitionFile = File(definitionFileName)
191             // Delete the File If exists
192             Files.deleteIfExists(definitionFile.toPath())
193
194             Files.write(definitionFile.toPath(), content.toByteArray(), StandardOpenOption.CREATE_NEW)
195             check(definitionFile.exists()) {
196                 throw BluePrintException(ErrorCode.BLUEPRINT_WRITING_FAIL.value, "couldn't write definition file under " +
197                         "path(${definitionFile.absolutePath})")
198             }
199         }
200
201         private fun writeTypeFile(definitionPath: String, type: String, content: String) = runBlocking {
202             val typeFile = File(definitionPath.plus(File.separator).plus("$type.json"))
203
204             Files.write(typeFile.toPath(), content.toByteArray(), StandardOpenOption.CREATE_NEW)
205             check(typeFile.exists()) {
206                 throw BluePrintException(ErrorCode.BLUEPRINT_WRITING_FAIL.value, "couldn't write $type.json file under " +
207                         "path(${typeFile.absolutePath})")
208             }
209         }
210
211         private fun getMetaDataContent(): String {
212             return "TOSCA-Meta-File-Version: 1.0.0" +
213                     "\nCSAR-Version: <VERSION>" +
214                     "\nCreated-By: <AUTHOR NAME>" +
215                     "\nEntry-Definitions: Definitions/<BLUEPRINT_NAME>.json" +
216                     "\nTemplate-Tags: <TAGS>"
217         }
218
219        
220         fun getBluePrintFile(fileName: String, targetPath: Path) : File {
221             val filePath = targetPath.resolve(fileName).toString()
222             val file = File(filePath)
223             check(file.exists()) {
224                 throw BluePrintException(ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get definition file under " +
225                         "path(${file.absolutePath})")
226             }
227             return file
228         }
229
230         fun getCbaStorageDirectory(path: String): Path {
231             check(StringUtils.isNotBlank(path)) {
232                 throw BluePrintException(ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get " +
233                         "Blueprint folder under path($path)")
234             }
235
236             val fileStorageLocation = Paths.get(path).toAbsolutePath().normalize()
237
238             if (!Files.exists(fileStorageLocation))
239                 Files.createDirectories(fileStorageLocation)
240
241             return fileStorageLocation
242         }
243
244         fun stripFileExtension(fileName: String): String {
245             val dotIndexe = fileName.lastIndexOf('.')
246
247             // In case dot is in first position, we are dealing with a hidden file rather than an extension
248             return if (dotIndexe > 0) fileName.substring(0, dotIndexe) else fileName
249         }
250
251     }
252 }