2 * Copyright © 2017-2018 AT&T Intellectual Property.
3 * Modifications Copyright © 2019 Bell Canada.
4 * Modifications Copyright © 2019 IBM.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 package org.onap.ccsdk.cds.controllerblueprints.core.utils
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
34 import java.io.FileFilter
35 import java.io.FileNotFoundException
37 import java.net.URLClassLoader
38 import java.nio.file.Files
39 import java.nio.file.NotDirectoryException
40 import java.nio.file.Path
41 import java.nio.file.Paths
42 import java.nio.file.StandardOpenOption
44 class BluePrintFileUtils {
47 const val COMPILED_JAR_SUFFIX = "cba-kts.jar"
49 private val log = LoggerFactory.getLogger(this::class.toString())
51 fun createEmptyBluePrint(basePath: String) {
53 val blueprintDir = File(basePath)
54 FileUtils.deleteDirectory(blueprintDir)
56 Files.createDirectories(blueprintDir.toPath())
58 val metaDataDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_METADATA_DIR))
59 Files.createDirectories(metaDataDir.toPath())
62 blueprintDir.absolutePath.plus(File.separator).plus(
64 .TOSCA_METADATA_ENTRY_DEFINITION_FILE
67 Files.write(metaFile.toPath(), getMetaDataContent().toByteArray(), StandardOpenOption.CREATE_NEW)
69 val definitionsDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR))
70 Files.createDirectories(definitionsDir.toPath())
72 val scriptsDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_SCRIPTS_DIR))
73 Files.createDirectories(scriptsDir.toPath())
75 val plansDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_PLANS_DIR))
76 Files.createDirectories(plansDir.toPath())
78 val templatesDir = File(blueprintDir.absolutePath.plus(File.separator).plus(BluePrintConstants.TOSCA_TEMPLATES_DIR))
79 Files.createDirectories(templatesDir.toPath())
82 fun copyBluePrint(sourcePath: String, targetPath: String) {
83 val sourceFile = File(sourcePath)
84 val targetFile = File(targetPath)
85 sourceFile.copyRecursively(targetFile, true)
88 fun deleteBluePrintTypes(basePath: String) {
89 val definitionPath = basePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR)
90 log.info("deleting definition types under : $definitionPath")
92 val definitionDir = File(definitionPath)
93 // Find the Type Definitions
94 val fileFilter = FileFilter { pathname -> pathname.absolutePath.endsWith("_types.json") }
95 // Delete the Type Files
96 definitionDir.listFiles(fileFilter).forEach {
97 Files.deleteIfExists(it.toPath())
101 fun writeEnhancedBluePrint(blueprintContext: BluePrintContext) {
103 // Write Blueprint Types
104 writeBluePrintTypes(blueprintContext)
105 // Re Populate the Imports
106 populateDefaultImports(blueprintContext)
107 // Rewrite the Entry Definition Files
108 writeEntryDefinitionFile(blueprintContext)
111 fun writeBluePrintTypes(blueprintContext: BluePrintContext) {
113 val basePath = blueprintContext.rootPath
114 val definitionPath = basePath.plus(File.separator).plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR)
115 val definitionDir = File(definitionPath)
117 check(definitionDir.exists()) {
118 throw BluePrintException(
119 ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get definition file under " +
120 "path(${definitionDir.absolutePath})"
124 blueprintContext.serviceTemplate.dataTypes?.let {
125 val dataTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_DATA_TYPES, it.toSortedMap(), true)
126 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_DATA_TYPES, dataTypesContent)
129 blueprintContext.serviceTemplate.relationshipTypes?.let {
130 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_RELATIONSHIP_TYPES, it.toSortedMap(), true)
131 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_RELATIONSHIP_TYPES, nodeTypesContent)
134 blueprintContext.serviceTemplate.artifactTypes?.let {
135 val artifactTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_ARTIFACT_TYPES, it.toSortedMap(), true)
136 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_ARTIFACT_TYPES, artifactTypesContent)
139 blueprintContext.serviceTemplate.nodeTypes?.let {
140 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_NODE_TYPES, it.toSortedMap(), true)
141 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_NODE_TYPES, nodeTypesContent)
144 blueprintContext.serviceTemplate.policyTypes?.let {
145 val nodeTypesContent = JacksonUtils.getWrappedJson(BluePrintConstants.PATH_POLICY_TYPES, it.toSortedMap(), true)
146 writeTypeFile(definitionDir.absolutePath, BluePrintConstants.PATH_POLICY_TYPES, nodeTypesContent)
150 private fun populateDefaultImports(blueprintContext: BluePrintContext) {
151 // Get the Default Types
152 val types = arrayListOf(
153 BluePrintConstants.PATH_DATA_TYPES, BluePrintConstants.PATH_RELATIONSHIP_TYPES,
154 BluePrintConstants.PATH_ARTIFACT_TYPES, BluePrintConstants.PATH_NODE_TYPES,
155 BluePrintConstants.PATH_POLICY_TYPES
158 // Clean Type Imports
159 cleanImportTypes(blueprintContext.serviceTemplate)
161 val imports = mutableListOf<ImportDefinition>()
162 types.forEach { typeName ->
163 val import = ImportDefinition()
164 import.file = BluePrintConstants.TOSCA_DEFINITIONS_DIR.plus("/$typeName.json")
168 blueprintContext.serviceTemplate.imports = imports
171 fun cleanImportTypes(serviceTemplate: ServiceTemplate) {
172 // Clean the Type imports
173 val toDeleteTypes = serviceTemplate.imports?.filter {
174 it.file.endsWith("_types.json")
177 if (toDeleteTypes != null && toDeleteTypes.isNotEmpty()) {
178 serviceTemplate.imports?.removeAll(toDeleteTypes)
183 * Re Generate the Blueprint Service Template Definition file based on BluePrint Context.
185 private fun writeEntryDefinitionFile(blueprintContext: BluePrintContext) {
187 val absoluteEntryDefinitionFile = blueprintContext.rootPath.plus(File.separator).plus(blueprintContext.entryDefinition)
189 val serviceTemplate = blueprintContext.serviceTemplate
191 // Clone the Service Template
192 val writeServiceTemplate = serviceTemplate.clone()
193 writeServiceTemplate.dataTypes = null
194 writeServiceTemplate.artifactTypes = null
195 writeServiceTemplate.policyTypes = null
196 writeServiceTemplate.relationshipTypes = null
197 writeServiceTemplate.nodeTypes = null
199 // Write the Service Template
200 writeDefinitionFile(absoluteEntryDefinitionFile, JacksonUtils.getJson(writeServiceTemplate, true))
203 fun writeDefinitionFile(definitionFileName: String, content: String) = runBlocking {
204 val definitionFile = File(definitionFileName)
205 // Delete the File If exists
206 Files.deleteIfExists(definitionFile.toPath())
208 Files.write(definitionFile.toPath(), content.toByteArray(), StandardOpenOption.CREATE_NEW)
209 check(definitionFile.exists()) {
210 throw BluePrintException(
211 ErrorCode.BLUEPRINT_WRITING_FAIL.value, "couldn't write definition file under " +
212 "path(${definitionFile.absolutePath})"
217 private fun writeTypeFile(definitionPath: String, type: String, content: String) = runBlocking {
218 val typeFile = File(definitionPath.plus(File.separator).plus("$type.json"))
220 Files.write(typeFile.toPath(), content.toByteArray(), StandardOpenOption.CREATE_NEW)
221 check(typeFile.exists()) {
222 throw BluePrintException(
223 ErrorCode.BLUEPRINT_WRITING_FAIL.value, "couldn't write $type.json file under " +
224 "path(${typeFile.absolutePath})"
229 private fun getMetaDataContent(): String {
230 return "TOSCA-Meta-File-Version: 1.0.0" +
231 "\nCSAR-Version: <VERSION>" +
232 "\nCreated-By: <AUTHOR NAME>" +
233 "\nEntry-Definitions: Definitions/<BLUEPRINT_NAME>.json" +
234 "\nTemplate-Name: <BLUEPRINT_NAME>" +
235 "\nTemplate-Tags: <BLUEPRINT_VERSION>" +
236 "\nTemplate-Tags: <TAGS>"
239 fun getBluePrintFile(fileName: String, targetPath: Path): File {
240 val filePath = targetPath.resolve(fileName).toString()
241 val file = File(filePath)
242 check(file.exists()) {
243 throw BluePrintException(
244 ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get definition file under " +
245 "path(${file.absolutePath})"
251 fun getCbaStorageDirectory(path: String): Path {
252 check(StringUtils.isNotBlank(path)) {
253 throw BluePrintException(
254 ErrorCode.BLUEPRINT_PATH_MISSING.value, "couldn't get " +
255 "Blueprint folder under path($path)"
259 val fileStorageLocation = Paths.get(path).toAbsolutePath().normalize()
261 if (!Files.exists(fileStorageLocation))
262 Files.createDirectories(fileStorageLocation)
264 return fileStorageLocation
267 fun compileCacheKey(basePath: String): String {
268 return normalizedPathName(basePath)
271 private fun compileJarFileName(artifactName: String, artifactVersion: String): String {
272 return "$artifactName-$artifactVersion-$COMPILED_JAR_SUFFIX"
275 fun compileJarFilePathName(basePath: String, artifactName: String, artifactVersion: String): String {
276 return normalizedPathName(
277 basePath, BluePrintConstants.TOSCA_SCRIPTS_KOTLIN_DIR,
278 compileJarFileName(artifactName, artifactVersion)
282 fun compileJarFile(basePath: String, artifactName: String, artifactVersion: String): File {
283 return normalizedFile(
284 compileJarFilePathName(
286 artifactName, artifactVersion
291 fun stripFileExtension(fileName: String): String {
292 val dotIndexe = fileName.lastIndexOf('.')
294 // In case dot is in first position, we are dealing with a hidden file rather than an extension
295 return if (dotIndexe > 0) fileName.substring(0, dotIndexe) else fileName
298 fun getURLClassLoaderFromDirectory(directory: File): URLClassLoader {
299 if (!directory.exists()) {
300 throw FileNotFoundException(directory.absolutePath)
301 } else if (!directory.isDirectory) {
302 throw NotDirectoryException(directory.absolutePath)
305 val urls = arrayListOf<URL>()
306 directory.walkTopDown()
307 .filter { it.name.endsWith(COMPILED_JAR_SUFFIX) }
309 log.debug("Adding (${it.absolutePath}) to classLoader (${directory.absolutePath})")
311 urls.add(it.toURI().toURL())
313 return URLClassLoader(urls.toTypedArray(), this.javaClass.classLoader)
316 fun getURLClassLoaderFromDirectory(path: String): URLClassLoader {
317 val directory = normalizedFile(path)
318 return getURLClassLoaderFromDirectory(directory)