From 04425ebaae2abc1862160acc7674205377078b4f Mon Sep 17 00:00:00 2001 From: "Muthuramalingam, Brinda Santh(bs2796)" Date: Tue, 4 Dec 2018 10:25:44 -0500 Subject: Add Blueprint Runtime Input/Output logic Change-Id: I0355e78862096b7b4074faa882d66ce27d6e1844 Issue-ID: CCSDK-670 Signed-off-by: Muthuramalingam, Brinda Santh(bs2796) --- .../core/BluePrintConstants.kt | 3 + .../controllerblueprints/core/CustomFunctions.kt | 20 ++- .../core/service/BluePrintContext.kt | 2 + .../core/service/BluePrintRuntimeService.kt | 34 +++-- .../core/service/PropertyAssignmentService.kt | 3 +- .../core/utils/BluePrintArchiveUtils.kt | 148 +++++++++++++++++++++ 6 files changed, 190 insertions(+), 20 deletions(-) create mode 100644 components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/utils/BluePrintArchiveUtils.kt (limited to 'components/core/src') diff --git a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/BluePrintConstants.kt b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/BluePrintConstants.kt index 0517e90b..167496eb 100644 --- a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/BluePrintConstants.kt +++ b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/BluePrintConstants.kt @@ -29,6 +29,9 @@ object BluePrintConstants { const val RESPONSE_HEADER_PATCH_VERSION: String = "X-PatchVersion" const val RESPONSE_HEADER_LATEST_VERSION: String = "X-LatestVersion" + const val STATUS_SUCCESS: String = "success" + const val STATUS_FAILURE: String = "failure" + const val TYPE_DEFAULT: String = "default" const val DATA_TYPE_STRING: String = "string" diff --git a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/CustomFunctions.kt b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/CustomFunctions.kt index c32e15f8..2329fc93 100644 --- a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/CustomFunctions.kt +++ b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/CustomFunctions.kt @@ -75,17 +75,17 @@ fun MutableMap.castValue(key: String, valueType: KClass) fun MutableMap.putJsonElement(key: String, value: Any) { when (value) { is JsonNode -> - this.put(key, value) + this[key] = value is String -> - this.put(key, TextNode(value)) + this[key] = TextNode(value) is Boolean -> - this.put(key, BooleanNode.valueOf(value)) + this[key] = BooleanNode.valueOf(value) is Int -> - this.put(key, IntNode.valueOf(value.toInt())) + this[key] = IntNode.valueOf(value.toInt()) is Double -> - this.put(key, DoubleNode.valueOf(value.toDouble())) + this[key] = DoubleNode.valueOf(value.toDouble()) else -> - this.put(key, JacksonUtils.jsonNodeFromObject(value)) + this[key] = JacksonUtils.jsonNodeFromObject(value) } } @@ -97,6 +97,14 @@ fun MutableMap.getAsBoolean(key: String): Boolean { return this[key]?.asBoolean() ?: throw BluePrintException("couldn't find value for key($key)") } +fun MutableMap.getAsInt(key: String): Int { + return this[key]?.asInt() ?: throw BluePrintException("couldn't find value for key($key)") +} + +fun MutableMap.getAsDouble(key: String): Double { + return this[key]?.asDouble() ?: throw BluePrintException("couldn't find value for key($key)") +} + // Checks fun checkNotEmpty(value: String?): Boolean { diff --git a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/BluePrintContext.kt b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/BluePrintContext.kt index cce6d904..84af3f98 100644 --- a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/BluePrintContext.kt +++ b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/BluePrintContext.kt @@ -57,6 +57,8 @@ class BluePrintContext(val serviceTemplate: ServiceTemplate) { fun workflowByName(workFlowName: String): Workflow = workflows?.get(workFlowName) ?: throw BluePrintException("could't get workflow($workFlowName)") + fun workflowInputs(workFlowName: String) = workflowByName(workFlowName).inputs + fun workflowStepByName(workFlowName: String, stepName: String): Step { return workflowByName(workFlowName).steps?.get(stepName) ?: throw BluePrintException("could't get step($stepName) for workflow($workFlowName)") diff --git a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/BluePrintRuntimeService.kt b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/BluePrintRuntimeService.kt index 84ba1047..448a06a8 100644 --- a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/BluePrintRuntimeService.kt +++ b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/BluePrintRuntimeService.kt @@ -25,7 +25,6 @@ import com.fasterxml.jackson.databind.node.NullNode import com.fasterxml.jackson.databind.node.ObjectNode import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintConstants -import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.apps.controllerblueprints.core.data.ArtifactDefinition import org.onap.ccsdk.apps.controllerblueprints.core.data.NodeTemplate @@ -211,15 +210,13 @@ open class DefaultBluePrintRuntimeService(private var id: String, private var bl val propertyAssignments: MutableMap = bluePrintContext.nodeTemplateInterfaceOperationInputs(nodeTemplateName, interfaceName, operationName) as? MutableMap - ?: throw BluePrintException(String.format("failed to get input definitions for node template (%s), " + - "interface name (%s), operationName(%s)", nodeTemplateName, interfaceName, operationName)) + ?: hashMapOf() val nodeTypeName = bluePrintContext.nodeTemplateByName(nodeTemplateName).type val nodeTypeInterfaceOperationInputs: MutableMap = bluePrintContext.nodeTypeInterfaceOperationInputs(nodeTypeName, interfaceName, operationName) - ?: throw BluePrintException(String.format("failed to get input definitions for node type (%s), " + - "interface name (%s), operationName(%s)", nodeTypeName, interfaceName, operationName)) + ?: hashMapOf() log.info("input definition for node template ({}), values ({})", nodeTemplateName, propertyAssignments) @@ -258,15 +255,13 @@ open class DefaultBluePrintRuntimeService(private var id: String, private var bl val propertyAssignments: MutableMap = bluePrintContext.nodeTemplateInterfaceOperationOutputs(nodeTemplateName, interfaceName, operationName) as? MutableMap - ?: throw BluePrintException(String.format("failed to get output definitions for node template (%s), " + - "interface name (%s), operationName(%s)", nodeTemplateName, interfaceName, operationName)) + ?: hashMapOf() val nodeTypeName = bluePrintContext.nodeTemplateByName(nodeTemplateName).type val nodeTypeInterfaceOperationOutputs: MutableMap = bluePrintContext.nodeTypeInterfaceOperationOutputs(nodeTypeName, interfaceName, operationName) - ?: throw BluePrintException(String.format("failed to get input definitions for node type (%s), " + - "interface name (%s), operationName(%s)", nodeTypeName, interfaceName, operationName)) + ?: hashMapOf() // Iterate Node Type Properties nodeTypeInterfaceOperationOutputs.forEach { nodeTypePropertyName, nodeTypeProperty -> @@ -435,10 +430,25 @@ open class DefaultBluePrintRuntimeService(private var id: String, private var bl override fun assignWorkflowInputs(workflowName: String, jsonNode: JsonNode) { log.info("assign workflow {} input value ({})", workflowName, jsonNode.toString()) + val dynamicInputPropertiesName = "$workflowName-properties" + bluePrintContext.workflowByName(workflowName).inputs?.forEach { propertyName, property -> - val valueNode: JsonNode = jsonNode.at(BluePrintConstants.PATH_DIVIDER + propertyName) - ?: NullNode.getInstance() - setInputValue(propertyName, property, valueNode) + if (propertyName != dynamicInputPropertiesName) { + val valueNode: JsonNode = jsonNode.at(BluePrintConstants.PATH_DIVIDER + propertyName) + ?: NullNode.getInstance() + setInputValue(propertyName, property, valueNode) + } + } + + val workflowDynamicInputs: JsonNode? = jsonNode.get(dynamicInputPropertiesName) + + workflowDynamicInputs?.let { + bluePrintContext.dataTypeByName(dynamicInputPropertiesName)?.properties?.forEach { propertyName, property -> + val valueNode: JsonNode = workflowDynamicInputs.at(BluePrintConstants.PATH_DIVIDER + propertyName) + ?: NullNode.getInstance() + setInputValue(propertyName, property, valueNode) + + } } } diff --git a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/PropertyAssignmentService.kt b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/PropertyAssignmentService.kt index 947eb41e..36c141f5 100644 --- a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/PropertyAssignmentService.kt +++ b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/service/PropertyAssignmentService.kt @@ -197,8 +197,7 @@ If Property Assignment is Expression. } fun artifactContent(artifactDefinition: ArtifactDefinition): String { - val bluePrintBasePath: String = bluePrintRuntimeService.get(BluePrintConstants.PROPERTY_BLUEPRINT_BASE_PATH)?.asText() - ?: throw BluePrintException("failed to get property (${BluePrintConstants.PROPERTY_BLUEPRINT_BASE_PATH}) from getStore") + val bluePrintBasePath: String = bluePrintContext.rootPath if (artifactDefinition.repository != null) { TODO() diff --git a/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/utils/BluePrintArchiveUtils.kt b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/utils/BluePrintArchiveUtils.kt new file mode 100644 index 00000000..f02524ff --- /dev/null +++ b/components/core/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/core/utils/BluePrintArchiveUtils.kt @@ -0,0 +1,148 @@ +/* + * Copyright © 2017-2018 AT&T Intellectual Property. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onap.ccsdk.apps.controllerblueprints.core.utils + +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream +import org.apache.commons.io.IOUtils +import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintProcessorException +import java.io.* +import java.nio.charset.Charset +import java.util.zip.ZipFile + +class BluePrintArchiveUtils { + + companion object { + + + fun compress(source: String, destination: String, absolute: Boolean): Boolean { + val rootDir = File(source) + val saveFile = File(destination) + return compress(rootDir, saveFile, absolute) + } + + /** + * Create a new Zip from a root directory + * + * @param directory the base directory + * @param filename the output filename + * @param absolute store absolute filepath (from directory) or only filename + * @return True if OK + */ + fun compress(source: File, destination: File, absolute: Boolean): Boolean { + // recursive call + val zaos: ZipArchiveOutputStream + try { + zaos = ZipArchiveOutputStream(FileOutputStream(destination)) + } catch (e: FileNotFoundException) { + return false + } + + try { + recurseFiles(source, source, zaos, absolute) + } catch (e2: IOException) { + try { + zaos.close() + } catch (e: IOException) { + // ignore + } + + return false + } + + try { + zaos.finish() + } catch (e1: IOException) { + // ignore + } + + try { + zaos.flush() + } catch (e: IOException) { + // ignore + } + + try { + zaos.close() + } catch (e: IOException) { + // ignore + } + + return true + } + + /** + * Recursive traversal to add files + * + * @param root + * @param file + * @param zaos + * @param absolute + * @throws IOException + */ + @Throws(IOException::class) + private fun recurseFiles(root: File, file: File, zaos: ZipArchiveOutputStream, + absolute: Boolean) { + if (file.isDirectory) { + // recursive call + val files = file.listFiles() + for (file2 in files!!) { + recurseFiles(root, file2, zaos, absolute) + } + } else if (!file.name.endsWith(".zip") && !file.name.endsWith(".ZIP")) { + var filename: String? = null + if (absolute) { + filename = file.absolutePath.substring(root.absolutePath.length) + } else { + filename = file.name + } + val zae = ZipArchiveEntry(filename) + zae.setSize(file.length()) + zaos.putArchiveEntry(zae) + val fis = FileInputStream(file) + IOUtils.copy(fis, zaos) + zaos.closeArchiveEntry() + } + } + + + fun deCompress(zipFile: File, targetPath: String): File { + val zip = ZipFile(zipFile, Charset.defaultCharset()) + val enumeration = zip.entries() + while (enumeration.hasMoreElements()) { + val entry = enumeration.nextElement() + val destFilePath = File(targetPath, entry.name) + destFilePath.parentFile.mkdirs() + if (entry.isDirectory) + continue + val bufferedIs = BufferedInputStream(zip.getInputStream(entry)) + bufferedIs.use { + destFilePath.outputStream().buffered(1024).use { bos -> + bufferedIs.copyTo(bos) + } + } + } + + val destinationDir = File(targetPath) + check(destinationDir.isDirectory && destinationDir.exists()) { + throw BluePrintProcessorException("failed to decompress blueprint(${zipFile.absolutePath}) to ($targetPath) ") + } + return destinationDir + } + } + +} \ No newline at end of file -- cgit 1.2.3-korg