Improve blueprint save 89/83389/3
authorMuthuramalingam, Brinda Santh <brindasanth@in.ibm.com>
Mon, 25 Mar 2019 21:01:08 +0000 (17:01 -0400)
committerMuthuramalingam, Brinda Santh <brindasanth@in.ibm.com>
Wed, 27 Mar 2019 17:23:06 +0000 (13:23 -0400)
Change-Id: Ibac2ef9cd7e217db809a6a695ea0ee39a6bd2e21
Issue-ID: CCSDK-1137
Signed-off-by: Muthuramalingam, Brinda Santh <brindasanth@in.ibm.com>
27 files changed:
components/model-catalog/proto-definition/proto/BluePrintManagement.proto
ms/blueprintsprocessor/application/src/test/resources/application.properties
ms/blueprintsprocessor/modules/commons/db-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImpl.kt
ms/blueprintsprocessor/modules/commons/db-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImplTest.kt
ms/blueprintsprocessor/modules/commons/db-lib/src/test/resources/application-test.properties
ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/BluePrintCoreConfiguration.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintManagementGRPCHandler.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintManagementGRPCHandlerTest.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/resources/application-test.properties
ms/controllerblueprints/application/src/main/resources/application-dev.properties
ms/controllerblueprints/application/src/main/resources/application.properties
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/FileExtensionFunctions.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/config/BluePrintLoadConfiguration.kt
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/interfaces/BluePrintCatalogService.kt
ms/controllerblueprints/modules/db-resources/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/db/resources/BlueprintCatalogServiceImpl.kt
ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/service/load/BluePrintCatalogLoadService.kt [new file with mode: 0644]
ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/ControllerBluePrintCoreConfiguration.kt
ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/controller/BlueprintModelController.kt
ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/handler/BluePrintModelHandler.kt
ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/load/BluePrintCatalogLoadService.kt
ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/load/ControllerBlueprintCatalogServiceImpl.kt
ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/utils/BluePrintEnhancerUtils.kt
ms/controllerblueprints/modules/service/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/controller/BlueprintModelControllerTest.kt
ms/controllerblueprints/modules/service/src/test/resources/application.properties

index 4062a8c..3349443 100644 (file)
@@ -3,11 +3,15 @@ import "BluePrintCommon.proto";
 option java_multiple_files = true;
 package org.onap.ccsdk.cds.controllerblueprints.management.api;
 
-message BluePrintManagementInput {
+message BluePrintUploadInput {
+  org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader commonHeader = 1;
+  FileChunk fileChunk = 2;
+}
+
+message BluePrintRemoveInput {
   org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader commonHeader = 1;
   string blueprintName = 2;
   string blueprintVersion = 3;
-  FileChunk fileChunk = 4;
 }
 
 message BluePrintManagementOutput {
@@ -20,6 +24,6 @@ message FileChunk {
 }
 
 service BluePrintManagementService {
-  rpc uploadBlueprint (BluePrintManagementInput) returns (BluePrintManagementOutput);
-  rpc removeBlueprint (BluePrintManagementInput) returns (BluePrintManagementOutput);
+  rpc uploadBlueprint (BluePrintUploadInput) returns (BluePrintManagementOutput);
+  rpc removeBlueprint (BluePrintRemoveInput) returns (BluePrintManagementOutput);
 }
index fc6f729..3078505 100644 (file)
@@ -23,6 +23,7 @@ blueprintsprocessor.grpcPort=9111
 # Blueprint Processor File Execution and Handling Properties
 blueprintsprocessor.blueprintDeployPath=/opt/app/onap/blueprints/deploy
 blueprintsprocessor.blueprintArchivePath=/opt/app/onap/blueprints/archive
+blueprintsprocessor.blueprintWorkingPath=/opt/app/onap/blueprints/work
 # Primary Database Configuration
 blueprintsprocessor.db.primary.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
 blueprintsprocessor.db.primary.username=sa
index 0a62500..3234c9a 100755 (executable)
 
 package org.onap.ccsdk.cds.blueprintsprocessor.db
 
-import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintCoreConfiguration
 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintProcessorModel
 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintProcessorModelContent
 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.repository.BlueprintProcessorModelRepository
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
+import org.onap.ccsdk.cds.controllerblueprints.core.*
 import org.onap.ccsdk.cds.controllerblueprints.core.common.ApplicationConstants
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintValidatorService
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintArchiveUtils
@@ -35,16 +34,16 @@ import org.springframework.stereotype.Service
 import java.io.File
 import java.nio.file.Files
 import java.nio.file.Path
-import java.nio.file.Paths
+import java.util.*
 
 /**
  * Similar/Duplicate implementation in [org.onap.ccsdk.cds.controllerblueprints.service.load.ControllerBlueprintCatalogServiceImpl]
  */
 @Service
 class BlueprintProcessorCatalogServiceImpl(bluePrintRuntimeValidatorService: BluePrintValidatorService,
-                                           private val blueprintConfig: BluePrintCoreConfiguration,
+                                           private val bluePrintPathConfiguration: BluePrintPathConfiguration,
                                            private val blueprintModelRepository: BlueprintProcessorModelRepository)
-    : BlueprintCatalogServiceImpl(bluePrintRuntimeValidatorService) {
+    : BlueprintCatalogServiceImpl(bluePrintPathConfiguration, bluePrintRuntimeValidatorService) {
 
     private val log = LoggerFactory.getLogger(BlueprintProcessorCatalogServiceImpl::class.toString())
 
@@ -53,33 +52,47 @@ class BlueprintProcessorCatalogServiceImpl(bluePrintRuntimeValidatorService: Blu
         log.info("BlueprintProcessorCatalogServiceImpl initialized")
     }
 
-    override fun delete(name: String, version: String) = blueprintModelRepository.deleteByArtifactNameAndArtifactVersion(name, version)
+    override suspend fun delete(name: String, version: String) {
+        // Cleaning Deployed Blueprint
+        deleteNBDir(bluePrintPathConfiguration.blueprintDeployPath, name, version)
+        // Cleaning Data Base
+        blueprintModelRepository
+                .deleteByArtifactNameAndArtifactVersion(name, version)
+    }
+
+
+    override suspend fun get(name: String, version: String, extract: Boolean): Path? {
 
+        val getId = UUID.randomUUID().toString()
+        var path = "${bluePrintPathConfiguration.blueprintArchivePath}/$getId/cba.zip"
 
-    override fun get(name: String, version: String, extract: Boolean): Path? {
-        var path = "${blueprintConfig.archivePath}/$name/$version.zip"
+        // TODO("Check first location for the file", If not get from database")
 
         blueprintModelRepository.findByArtifactNameAndArtifactVersion(name, version)?.also {
             it.blueprintModelContent.run {
-                val file = File(path)
-                file.parentFile.mkdirs()
-                file.createNewFile()
+                val file = normalizedFile(path)
+                file.parentFile.reCreateDirs()
+
                 file.writeBytes(this!!.content!!).let {
                     if (extract) {
-                        path = "${blueprintConfig.archivePath}/$name/$version"
+                        path = "${bluePrintPathConfiguration.blueprintDeployPath}/$name/$version"
                         BluePrintArchiveUtils.deCompress(file, path)
                     }
-                    return Paths.get(path)
+                    return normalizedPath(path)
                 }
             }
         }
         return null
     }
 
-    override fun save(metadata: MutableMap<String, String>, archiveFile: File) {
+    override suspend fun save(metadata: MutableMap<String, String>, archiveFile: File) {
         val artifactName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]
         val artifactVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]
 
+        check(archiveFile.isFile && !archiveFile.isDirectory) {
+            throw BluePrintException("Not a valid Archive file(${archiveFile.absolutePath})")
+        }
+
         blueprintModelRepository.findByArtifactNameAndArtifactVersion(artifactName!!, artifactVersion!!)?.let {
             log.info("Overwriting blueprint model :$artifactName::$artifactVersion")
             blueprintModelRepository.deleteByArtifactNameAndArtifactVersion(artifactName, artifactVersion)
index a9a2ae7..2fda159 100644 (file)
  */
 package org.onap.ccsdk.cds.blueprintsprocessor.db
 
+import kotlinx.coroutines.runBlocking
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.onap.ccsdk.cds.controllerblueprints.core.deleteDir
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
 import org.springframework.context.annotation.ComponentScan
 import org.springframework.test.context.TestPropertySource
 import org.springframework.test.context.junit4.SpringRunner
-import java.io.File
-import java.nio.file.Paths
+import kotlin.test.AfterTest
+import kotlin.test.BeforeTest
 import kotlin.test.assertTrue
 
 @RunWith(SpringRunner::class)
@@ -36,17 +39,30 @@ class BlueprintProcessorCatalogServiceImplTest {
     @Autowired
     lateinit var blueprintCatalog: BluePrintCatalogService
 
+    @BeforeTest
+    fun setup() {
+        deleteDir("target", "blueprints")
+    }
+
+    @AfterTest
+    fun cleanDir() {
+        deleteDir("target", "blueprints")
+    }
+
     @Test
     fun `test catalog service`() {
-        val file = Paths.get("./src/test/resources/test-cba.zip").toFile()
-        assertTrue(file.exists(), "couldnt get file ${file.absolutePath}")
+        runBlocking {
+            //FIXME("Create ZIP from test blueprints")
+
+            val file = normalizedFile("./src/test/resources/test-cba.zip")
+            assertTrue(file.exists(), "couldn't get file ${file.absolutePath}")
 
-        blueprintCatalog.saveToDatabase(file)
+            blueprintCatalog.saveToDatabase("1234", file)
 
-        blueprintCatalog.getFromDatabase("baseconfiguration", "1.0.0")
+            blueprintCatalog.getFromDatabase("baseconfiguration", "1.0.0")
 
-        blueprintCatalog.deleteFromDatabase("baseconfiguration", "1.0.0")
+            blueprintCatalog.deleteFromDatabase("baseconfiguration", "1.0.0")
 
-        File("./src/test/resources/baseconfiguration").deleteRecursively()
+        }
     }
 }
\ No newline at end of file
index 3ac7ec3..9dda71e 100644 (file)
@@ -25,3 +25,4 @@ blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.H2Dialect
 # Controller Blueprints Core Configuration
 blueprintsprocessor.blueprintDeployPath=./target/blueprints/deploy
 blueprintsprocessor.blueprintArchivePath=./target/blueprints/archive
+blueprintsprocessor.blueprintWorkingPath=./target/blueprints/work
index 03b847e..5f1ae7d 100644 (file)
 
 package org.onap.ccsdk.cds.blueprintsprocessor.core
 
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
 import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.beans.factory.annotation.Value
+import org.springframework.boot.context.properties.bind.Bindable
 import org.springframework.boot.context.properties.bind.Binder
 import org.springframework.boot.context.properties.source.ConfigurationPropertySources
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
 import org.springframework.core.env.Environment
+import org.springframework.stereotype.Service
 
 
 @Configuration
-open class BluePrintCoreConfiguration {
+open class BluePrintCoreConfiguration(private val bluePrintProperties: BlueprintProcessorProperties) {
 
-    @Value("\${blueprintsprocessor.blueprintDeployPath}")
-    lateinit var deployPath: String
+    companion object {
+        const val PREFIX_BLUEPRINT_PROCESSOR = "blueprintsprocessor"
+    }
 
-    @Value("\${blueprintsprocessor.blueprintArchivePath}")
-    lateinit var archivePath: String
+    @Bean
+    open fun bluePrintPathConfiguration(): BluePrintPathConfiguration {
+        return bluePrintProperties
+                .propertyBeanType(PREFIX_BLUEPRINT_PROCESSOR, BluePrintPathConfiguration::class.java)
+    }
 
 }
 
@@ -46,4 +52,11 @@ open class BlueprintPropertyConfiguration {
         val configurationPropertySource = ConfigurationPropertySources.get(environment)
         return Binder(configurationPropertySource)
     }
+}
+
+@Service
+open class BlueprintProcessorProperties(private var bluePrintPropertyBinder: Binder) {
+    fun <T> propertyBeanType(prefix: String, type: Class<T>): T {
+        return bluePrintPropertyBinder.bind(prefix, Bindable.of(type)).get()
+    }
 }
\ No newline at end of file
index 1fa1410..251ae2c 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright Â© 2017-2018 AT&T Intellectual Property.
  * Modifications Copyright Â© 2019 Bell Canada.
+ * Modifications Copyright Â© 2019 IBM.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,78 +20,87 @@ package org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api
 
 import io.grpc.StatusException
 import io.grpc.stub.StreamObserver
-import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintCoreConfiguration
+import kotlinx.coroutines.runBlocking
 import org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.utils.currentTimestamp
 import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader
 import org.onap.ccsdk.cds.controllerblueprints.common.api.Status
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
+import org.onap.ccsdk.cds.controllerblueprints.core.deleteDir
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
-import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementInput
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
+import org.onap.ccsdk.cds.controllerblueprints.core.reCreateDirs
 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementOutput
 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc
+import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintRemoveInput
+import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput
 import org.slf4j.LoggerFactory
 import org.springframework.security.access.prepost.PreAuthorize
 import org.springframework.stereotype.Service
 import java.io.File
+import java.util.*
 
 @Service
-open class BluePrintManagementGRPCHandler(private val bluePrintCoreConfiguration: BluePrintCoreConfiguration,
-                                     private val bluePrintCatalogService: BluePrintCatalogService)
+open class BluePrintManagementGRPCHandler(private val bluePrintPathConfiguration: BluePrintPathConfiguration,
+                                          private val bluePrintCatalogService: BluePrintCatalogService)
     : BluePrintManagementServiceGrpc.BluePrintManagementServiceImplBase() {
 
     private val log = LoggerFactory.getLogger(BluePrintManagementGRPCHandler::class.java)
 
     @PreAuthorize("hasRole('USER')")
-    override fun uploadBlueprint(request: BluePrintManagementInput, responseObserver: StreamObserver<BluePrintManagementOutput>) {
-        val blueprintName = request.blueprintName
-        val blueprintVersion = request.blueprintVersion
-        val blueprint = "blueprint $blueprintName:$blueprintVersion"
+    override fun uploadBlueprint(request: BluePrintUploadInput, responseObserver:
+    StreamObserver<BluePrintManagementOutput>) {
+        runBlocking {
+
+            log.info("request(${request.commonHeader.requestId})")
+            val uploadId = UUID.randomUUID().toString()
+            try {
+                val cbaFile = normalizedFile(bluePrintPathConfiguration.blueprintArchivePath, uploadId, "cba-zip")
+
+                saveToDisk(request, cbaFile)
+
+                val blueprintId = bluePrintCatalogService.saveToDatabase(uploadId, cbaFile)
+                responseObserver.onNext(successStatus("Successfully uploaded CBA($blueprintId)...", request.commonHeader))
+                responseObserver.onCompleted()
+            } catch (e: Exception) {
+                failStatus("request(${request.commonHeader.requestId}): Failed to upload CBA", e)
+            } finally {
+                deleteDir(bluePrintPathConfiguration.blueprintArchivePath, uploadId)
+                deleteDir(bluePrintPathConfiguration.blueprintWorkingPath, uploadId)
+            }
+        }
+    }
 
-        log.info("request(${request.commonHeader.requestId}): Received upload $blueprint")
+    @PreAuthorize("hasRole('USER')")
+    override fun removeBlueprint(request: BluePrintRemoveInput, responseObserver:
+    StreamObserver<BluePrintManagementOutput>) {
 
-        val blueprintArchivedFilePath = "${bluePrintCoreConfiguration.archivePath}/$blueprintName/$blueprintVersion/$blueprintName.zip"
-        try {
-            val blueprintArchivedFile = File(blueprintArchivedFilePath)
+        runBlocking {
+            val blueprintName = request.blueprintName
+            val blueprintVersion = request.blueprintVersion
+            val blueprint = "blueprint $blueprintName:$blueprintVersion"
 
-            saveToDisk(request, blueprintArchivedFile)
-            val blueprintId = bluePrintCatalogService.saveToDatabase(blueprintArchivedFile)
+            log.info("request(${request.commonHeader.requestId}): Received delete $blueprint")
 
-            File("${bluePrintCoreConfiguration.archivePath}/$blueprintName").deleteRecursively()
 
-            responseObserver.onNext(successStatus("Successfully uploaded $blueprint with id($blueprintId)", request.commonHeader))
-            responseObserver.onCompleted()
-        } catch (e: Exception) {
-            failStatus("request(${request.commonHeader.requestId}): Failed to upload $blueprint at path $blueprintArchivedFilePath", e)
+            try {
+                bluePrintCatalogService.deleteFromDatabase(blueprintName, blueprintVersion)
+                responseObserver.onNext(successStatus("Successfully deleted $blueprint", request.commonHeader))
+                responseObserver.onCompleted()
+            } catch (e: Exception) {
+                failStatus("request(${request.commonHeader.requestId}): Failed to delete $blueprint", e)
+            }
         }
     }
 
-    @PreAuthorize("hasRole('USER')")
-    override fun removeBlueprint(request: BluePrintManagementInput, responseObserver: StreamObserver<BluePrintManagementOutput>) {
-        val blueprintName = request.blueprintName
-        val blueprintVersion = request.blueprintVersion
-        val blueprint = "blueprint $blueprintName:$blueprintVersion"
-
-        log.info("request(${request.commonHeader.requestId}): Received delete $blueprint")
-
-        try {
-            bluePrintCatalogService.deleteFromDatabase(blueprintName, blueprintVersion)
-            responseObserver.onNext(successStatus("Successfully deleted $blueprint", request.commonHeader))
-            responseObserver.onCompleted()
-        } catch (e: Exception) {
-            failStatus("request(${request.commonHeader.requestId}): Failed to delete $blueprint", e)
-        }
-    }
+    private fun saveToDisk(request: BluePrintUploadInput, cbaFile: File) {
+        log.info("request(${request.commonHeader.requestId}): Writing CBA File under :${cbaFile.absolutePath}")
 
-    private fun saveToDisk(request: BluePrintManagementInput, blueprintDir: File) {
-        log.info("request(${request.commonHeader.requestId}): Writing CBA File under :${blueprintDir.absolutePath}")
-        if (blueprintDir.exists()) {
-            log.info("request(${request.commonHeader.requestId}): Re-creating blueprint directory(${blueprintDir.absolutePath})")
-            //FileUtils.deleteDirectory(blueprintDir.parentFile)
-            blueprintDir.parentFile.deleteRecursively()
-        }
-        blueprintDir.parentFile.mkdirs()
-        //FileUtils.forceMkdir(blueprintDir.parentFile)
-        blueprintDir.writeBytes(request.fileChunk.chunk.toByteArray()).apply {
-            log.info("request(${request.commonHeader.requestId}): CBA file(${blueprintDir.absolutePath} written successfully")
+        // Recreate Folder
+        cbaFile.parentFile.reCreateDirs()
+
+        // Write the File
+        cbaFile.writeBytes(request.fileChunk.chunk.toByteArray()).apply {
+            log.info("request(${request.commonHeader.requestId}): CBA file(${cbaFile.absolutePath} written successfully")
         }
 
     }
index 1039d5c..41e78e5 100644 (file)
@@ -27,7 +27,6 @@ import org.springframework.http.MediaType
 import org.springframework.http.codec.multipart.FilePart
 import org.springframework.security.access.prepost.PreAuthorize
 import org.springframework.web.bind.annotation.*
-import reactor.core.publisher.Mono
 
 @RestController
 @RequestMapping("/api/v1/execution-service")
@@ -46,11 +45,8 @@ open class ExecutionServiceController {
     @ApiOperation(value = "Upload CBA", notes = "Takes a File and load it in the runtime database")
     @ResponseBody
     @PreAuthorize("hasRole('USER')")
-    fun upload(@RequestPart("file") parts: Mono<FilePart>): Mono<String> {
-        return parts
-                .filter { it is FilePart }
-                .ofType(FilePart::class.java)
-                .flatMap(executionServiceHandler::upload)
+    fun upload(@RequestPart("file") filePart: FilePart): String = runBlocking {
+        executionServiceHandler.upload(filePart)
     }
 
     @RequestMapping(path = ["/process"], method = [RequestMethod.POST], produces = [MediaType.APPLICATION_JSON_VALUE])
index f3af254..bf0fb44 100644 (file)
@@ -22,44 +22,50 @@ import io.grpc.stub.StreamObserver
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.launch
-import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintCoreConfiguration
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ACTION_MODE_ASYNC
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ACTION_MODE_SYNC
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status
-import org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.utils.saveCBAFile
+import kotlinx.coroutines.reactive.awaitSingle
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.*
 import org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.utils.toProto
 import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
+import org.onap.ccsdk.cds.controllerblueprints.core.*
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
+import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintWorkflowExecutionService
-import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
 import org.slf4j.LoggerFactory
 import org.springframework.http.codec.multipart.FilePart
 import org.springframework.stereotype.Service
-import reactor.core.publisher.Mono
+import java.io.File
+import java.io.IOException
+import java.util.*
 import java.util.stream.Collectors
 
 @Service
-class ExecutionServiceHandler(private val bluePrintCoreConfiguration: BluePrintCoreConfiguration,
+class ExecutionServiceHandler(private val bluePrintPathConfiguration: BluePrintPathConfiguration,
                               private val bluePrintCatalogService: BluePrintCatalogService,
                               private val bluePrintWorkflowExecutionService
                               : BluePrintWorkflowExecutionService<ExecutionServiceInput, ExecutionServiceOutput>) {
 
     private val log = LoggerFactory.getLogger(ExecutionServiceHandler::class.toString())
 
-    fun upload(filePart: FilePart): Mono<String> {
+    suspend fun upload(filePart: FilePart): String {
+        val saveId = UUID.randomUUID().toString()
+        val blueprintArchive = normalizedPathName(bluePrintPathConfiguration.blueprintArchivePath, saveId)
+        val blueprintWorking = normalizedPathName(bluePrintPathConfiguration.blueprintWorkingPath, saveId)
         try {
-            val archivedPath = BluePrintFileUtils.getCbaStorageDirectory(bluePrintCoreConfiguration.archivePath)
-            val cbaPath = saveCBAFile(filePart, archivedPath)
-            bluePrintCatalogService.saveToDatabase(cbaPath.toFile()).let {
-                return Mono.just("{\"status\": \"Successfully uploaded blueprint with id($it)\"}")
-            }
-        } catch (e: Exception) {
-            return Mono.error<String>(BluePrintException("Error uploading the CBA file.", e))
+
+            val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
+            compressedFile.parentFile.reCreateNBDirs()
+            // Copy the File Part to Local File
+            copyFromFilePart(filePart, compressedFile)
+            // Save the Copied file to Database
+            return bluePrintCatalogService.saveToDatabase(saveId, compressedFile, false)
+        } catch (e: IOException) {
+            throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
+                    "Error in Upload CBA: ${e.message}", e)
+        } finally {
+            deleteNBDir(blueprintArchive)
+            deleteNBDir(blueprintWorking)
         }
     }
 
@@ -80,8 +86,8 @@ class ExecutionServiceHandler(private val bluePrintCoreConfiguration: BluePrintC
                 responseObserver.onCompleted()
             }
             else -> responseObserver.onNext(response(executionServiceInput,
-                "Failed to process request, 'actionIdentifiers.mode' not specified. Valid value are: 'sync' or 'async'.",
-                true).toProto());
+                    "Failed to process request, 'actionIdentifiers.mode' not specified. Valid value are: 'sync' or 'async'.",
+                    true).toProto());
         }
     }
 
@@ -100,7 +106,7 @@ class ExecutionServiceHandler(private val bluePrintCoreConfiguration: BluePrintC
         val blueprintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(requestId, basePath.toString())
 
         val output = bluePrintWorkflowExecutionService.executeBluePrintWorkflow(blueprintRuntimeService,
-            executionServiceInput, hashMapOf())
+                executionServiceInput, hashMapOf())
 
         val errors = blueprintRuntimeService.getBluePrintError().errors
         if (errors.isNotEmpty()) {
@@ -111,6 +117,12 @@ class ExecutionServiceHandler(private val bluePrintCoreConfiguration: BluePrintC
         return output
     }
 
+    private suspend fun copyFromFilePart(filePart: FilePart, targetFile: File): File {
+        return filePart.transferTo(targetFile)
+                .thenReturn(targetFile)
+                .awaitSingle()
+    }
+
     private fun setErrorStatus(errorMessage: String, status: Status) {
         status.errorMessage = errorMessage
         status.eventType = EventType.EVENT_COMPONENT_FAILURE.name
index a03ad9e..fd764d7 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright Â© 2017-2018 AT&T Intellectual Property.
  * Modifications Copyright Â© 2019 Bell Canada.
+ * Modifications Copyright Â© 2019 IBM.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,8 +24,11 @@ import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader
-import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementInput
+import org.onap.ccsdk.cds.controllerblueprints.core.deleteDir
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc
+import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintRemoveInput
+import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput
 import org.onap.ccsdk.cds.controllerblueprints.management.api.FileChunk
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
@@ -32,7 +36,6 @@ import org.springframework.context.annotation.ComponentScan
 import org.springframework.test.annotation.DirtiesContext
 import org.springframework.test.context.TestPropertySource
 import org.springframework.test.context.junit4.SpringRunner
-import java.io.File
 import kotlin.test.AfterTest
 import kotlin.test.BeforeTest
 import kotlin.test.assertEquals
@@ -55,25 +58,23 @@ class BluePrintManagementGRPCHandlerTest {
     fun init() {
         // Create a server, add service, start, and register for automatic graceful shutdown.
         grpcServerRule.serviceRegistry.addService(bluePrintManagementGRPCHandler)
+        deleteDir("target", "blueprints")
     }
 
     @AfterTest
     fun cleanDir() {
-        //TODO It's giving fluctuating results, need to look for another way to cleanup
-        // works sometimes otherwise results IO Exception
-        // Most probably bufferReader stream is not getting closed when cleanDir is getting invoked
-        File("./target/blueprints").deleteRecursively()
+        deleteDir("target", "blueprints")
     }
 
     @Test
     fun `test upload blueprint`() {
         val blockingStub = BluePrintManagementServiceGrpc.newBlockingStub(grpcServerRule.channel)
         val id = "123_upload"
-        val req = createInputRequest(id)
+        val req = createUploadInputRequest(id)
         val output = blockingStub.uploadBlueprint(req)
 
         assertEquals(200, output.status.code)
-        assertTrue(output.status.message.contains("Successfully uploaded blueprint sample:1.0.0 with id("))
+        assertTrue(output.status.message.contains("Successfully uploaded CBA"))
         assertEquals(id, output.commonHeader.requestId)
     }
 
@@ -81,19 +82,20 @@ class BluePrintManagementGRPCHandlerTest {
     fun `test delete blueprint`() {
         val blockingStub = BluePrintManagementServiceGrpc.newBlockingStub(grpcServerRule.channel)
         val id = "123_delete"
-        val req = createInputRequest(id)
+        val req = createUploadInputRequest(id)
 
         var output = blockingStub.uploadBlueprint(req)
         assertEquals(200, output.status.code)
-        assertTrue(output.status.message.contains("Successfully uploaded blueprint sample:1.0.0 with id("))
+        assertTrue(output.status.message.contains("Successfully uploaded CBA"))
         assertEquals(id, output.commonHeader.requestId)
 
-        output = blockingStub.removeBlueprint(req)
+        val removeReq = createRemoveInputRequest(id)
+        output = blockingStub.removeBlueprint(removeReq)
         assertEquals(200, output.status.code)
     }
 
-    private fun createInputRequest(id: String): BluePrintManagementInput {
-        val file = File("./src/test/resources/test-cba.zip")
+    private fun createUploadInputRequest(id: String): BluePrintUploadInput {
+        val file = normalizedFile("./src/test/resources/test-cba.zip")
         assertTrue(file.exists(), "couldnt get file ${file.absolutePath}")
 
         val commonHeader = CommonHeader
@@ -106,11 +108,24 @@ class BluePrintManagementGRPCHandlerTest {
         val fileChunk = FileChunk.newBuilder().setChunk(ByteString.copyFrom(file.inputStream().readBytes()))
                 .build()
 
-        return BluePrintManagementInput.newBuilder()
+        return BluePrintUploadInput.newBuilder()
+                .setCommonHeader(commonHeader)
+                .setFileChunk(fileChunk)
+                .build()
+    }
+
+    private fun createRemoveInputRequest(id: String): BluePrintRemoveInput {
+        val commonHeader = CommonHeader
+                .newBuilder()
+                .setTimestamp("2012-04-23T18:25:43.511Z")
+                .setOriginatorId("System")
+                .setRequestId(id)
+                .setSubRequestId("1234-56").build()
+
+        return BluePrintRemoveInput.newBuilder()
                 .setCommonHeader(commonHeader)
                 .setBlueprintName("sample")
                 .setBlueprintVersion("1.0.0")
-                .setFileChunk(fileChunk)
                 .build()
     }
 }
index b131fb7..d14761c 100644 (file)
 
 package org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api
 
+import kotlinx.coroutines.reactive.awaitSingle
+import kotlinx.coroutines.runBlocking
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintCoreConfiguration
 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.controllerblueprints.core.deleteDir
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
 import org.springframework.beans.factory.annotation.Autowired
@@ -33,9 +36,13 @@ import org.springframework.test.context.ContextConfiguration
 import org.springframework.test.context.TestPropertySource
 import org.springframework.test.context.junit4.SpringRunner
 import org.springframework.test.web.reactive.server.WebTestClient
+import org.springframework.test.web.reactive.server.returnResult
 import org.springframework.web.reactive.function.BodyInserters
 import java.nio.file.Files
 import java.nio.file.Paths
+import java.util.*
+import kotlin.test.AfterTest
+import kotlin.test.BeforeTest
 import kotlin.test.assertTrue
 
 @RunWith(SpringRunner::class)
@@ -50,40 +57,61 @@ class ExecutionServiceHandlerTest {
     @Autowired
     lateinit var webTestClient: WebTestClient
 
+    @BeforeTest
+    fun init() {
+        deleteDir("target", "blueprints")
+    }
+
+    @AfterTest
+    fun cleanDir() {
+        deleteDir("target", "blueprints")
+    }
+
 
     @Test
     fun `test rest upload blueprint`() {
-        val file = Paths.get("./src/test/resources/test-cba.zip").toFile()
-        assertTrue(file.exists(), "couldnt get file ${file.absolutePath}")
+        runBlocking {
+            val file = Paths.get("./src/test/resources/test-cba.zip").toFile()
+            assertTrue(file.exists(), "couldn't get file ${file.absolutePath}")
+
+            val body = MultipartBodyBuilder().apply {
+                part("file", object : ByteArrayResource(Files.readAllBytes(Paths.get("./src/test/resources/test-cba.zip"))) {
+                    override fun getFilename(): String {
+                        return "test-cba.zip"
+                    }
+                })
+            }.build()
 
-        val body = MultipartBodyBuilder().apply {
-            part("file", object : ByteArrayResource(Files.readAllBytes(Paths.get("./src/test/resources/test-cba.zip"))) {
-                override fun getFilename(): String {
-                    return "test-cba.zip"
-                }
-            })
-        }.build()
+            webTestClient
+                    .post()
+                    .uri("/api/v1/execution-service/upload")
+                    .body(BodyInserters.fromMultipartData(body))
+                    .exchange()
+                    .expectStatus().isOk
+                    .returnResult<String>()
+                    .responseBody
+                    .awaitSingle()
+        }
 
-        webTestClient
-                .post()
-                .uri("/api/v1/execution-service/upload")
-                .body(BodyInserters.fromMultipartData(body))
-                .exchange()
-                .expectStatus().isOk
     }
 
     @Test
     fun `test rest process`() {
-        val file = Paths.get("./src/test/resources/test-cba.zip").toFile()
-        assertTrue(file.exists(), "couldnt get file ${file.absolutePath}")
-        blueprintCatalog.saveToDatabase(file)
+        runBlocking {
+            val file = Paths.get("./src/test/resources/test-cba.zip").toFile()
+            assertTrue(file.exists(), "couldnt get file ${file.absolutePath}")
+            blueprintCatalog.saveToDatabase(UUID.randomUUID().toString(), file)
+
+            val executionServiceInput = JacksonUtils
+                    .readValueFromClassPathFile("execution-input/default-input.json",
+                            ExecutionServiceInput::class.java)!!
 
-        val executionServiceInput = JacksonUtils.readValueFromClassPathFile("execution-input/default-input.json", ExecutionServiceInput::class.java)!!
-        webTestClient
-                .post()
-                .uri("/api/v1/execution-service/process")
-                .body(BodyInserters.fromObject(executionServiceInput))
-                .exchange()
-                .expectStatus().isOk
+            webTestClient
+                    .post()
+                    .uri("/api/v1/execution-service/process")
+                    .body(BodyInserters.fromObject(executionServiceInput))
+                    .exchange()
+                    .expectStatus().isOk
+        }
     }
 }
\ No newline at end of file
index 6d8b62f..6705523 100644 (file)
@@ -25,6 +25,7 @@ blueprintsprocessor.db.primary.hibernateNamingStrategy=org.hibernate.cfg.Improve
 blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.H2Dialect
 # Controller Blueprints Core Configuration
 blueprintsprocessor.blueprintDeployPath=./target/blueprints/deploy
+blueprintsprocessor.blueprintWorkingPath=./target/blueprints/work
 blueprintsprocessor.blueprintArchivePath=./target/blueprints/archive
 
 # Python executor
index 7282d75..46218d6 100755 (executable)
@@ -53,7 +53,7 @@ resourceSourceMappings=processor-db=source-processor-db,input=source-input,defau
 # Controller Blueprints Core Configuration
 controllerblueprints.blueprintDeployPath=/etc/blueprints/deploy
 controllerblueprints.blueprintArchivePath=/etc/blueprints/archive
-controllerblueprints.blueprintEnrichmentPath=/etc/blueprints/enrichment
+controllerblueprints.blueprintWorkingPath=/etc/blueprints/work
 # Controller Blueprint Load Configurations
 controllerblueprints.loadInitialData=true
 controllerblueprints.loadBluePrint=false
index 5877ea5..b9c1d4f 100755 (executable)
@@ -57,7 +57,7 @@ resourceSourceMappings=processor-db=source-processor-db,input=source-input,defau
 # Controller Blueprints Core Configuration
 controllerblueprints.blueprintDeployPath=/etc/blueprints/deploy
 controllerblueprints.blueprintArchivePath=/etc/blueprints/archive
-controllerblueprints.blueprintEnrichmentPath=/etc/blueprints/enrichment
+controllerblueprints.blueprintWorkingPath=/etc/blueprints/work
 # Controller Blueprint Load Configurations
 # blueprints.load.initial-data may be overridden by ENV variables
 controllerblueprints.loadInitialData=true
index 6744b62..bda60ea 100644 (file)
@@ -84,6 +84,14 @@ fun normalizedPathName(path: String, vararg more: String?): String {
     return normalizedPath(path, *more).toString()
 }
 
+suspend fun File.reCreateNBDirs(): File = withContext(Dispatchers.IO) {
+    reCreateDirs()
+}
+
+suspend fun deleteNBDir(path: String, vararg more: String?) = withContext(Dispatchers.IO) {
+    normalizedFile(path, *more).deleteRecursively()
+}
+
 suspend fun File.readNBText(): String = withContext(Dispatchers.IO) {
     readText(Charset.defaultCharset())
 }
index 2815bad..8674c4d 100644 (file)
 
 package org.onap.ccsdk.cds.controllerblueprints.core.config
 
-open class BluePrintLoadConfiguration {
 
+open class BluePrintPathConfiguration {
     lateinit var blueprintDeployPath: String
     lateinit var blueprintArchivePath: String
-    lateinit var blueprintEnrichmentPath: String
+    lateinit var blueprintWorkingPath: String
+}
 
+
+open class BluePrintLoadConfiguration : BluePrintPathConfiguration() {
     var loadInitialData: Boolean = false
     var loadBluePrint: Boolean = false
     var loadBluePrintPaths: String? = null
index d71569e..9b4f6b5 100755 (executable)
@@ -16,8 +16,6 @@
 
 package org.onap.ccsdk.cds.controllerblueprints.core.interfaces
 
-import org.jetbrains.annotations.NotNull
-import org.jetbrains.annotations.Nullable
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
 import java.io.File
 import java.nio.file.Path
@@ -26,14 +24,14 @@ interface BluePrintCatalogService {
 
     /**
      * Save the CBA to database.
+     * @param processingId Processing Id
      * @param blueprintFile Either a directory, or an archive
      * @param validate whether to validate blueprint content. Default true.
      * @return The unique blueprint identifier
      * @throws BluePrintException if process failed
      */
-    @NotNull
     @Throws(BluePrintException::class)
-    fun saveToDatabase(@NotNull blueprintFile: File, @Nullable validate: Boolean = true): String
+    suspend fun saveToDatabase(processingId: String, blueprintFile: File, validate: Boolean = true): String
 
     /**
      * Retrieve the CBA from database either archived or extracted.
@@ -43,9 +41,9 @@ interface BluePrintCatalogService {
      * @return Path where CBA is located
      * @throws BluePrintException if process failed
      */
-    @NotNull
+
     @Throws(BluePrintException::class)
-    fun getFromDatabase(@NotNull name: String, @NotNull version: String, @Nullable extract: Boolean = true): Path
+    suspend fun getFromDatabase(name: String, version: String, extract: Boolean = true): Path
 
     /**
      * Delete the CBA from database.
@@ -53,7 +51,7 @@ interface BluePrintCatalogService {
      * @param version Version of the blueprint
      * @throws BluePrintException if process failed
      */
-    @NotNull
+
     @Throws(BluePrintException::class)
-    fun deleteFromDatabase(@NotNull name: String, @NotNull version: String)
+    suspend fun deleteFromDatabase(name: String, version: String)
 }
\ No newline at end of file
index 3be5648..9780bbd 100644 (file)
 
 package org.onap.ccsdk.cds.controllerblueprints.db.resources
 
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
+import org.onap.ccsdk.cds.controllerblueprints.core.*
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintValidatorService
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintArchiveUtils
-import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
+import org.slf4j.LoggerFactory
 import java.io.File
 import java.nio.file.Path
-import java.util.*
 import javax.persistence.MappedSuperclass
 
 @MappedSuperclass
-abstract class BlueprintCatalogServiceImpl(private val blueprintValidator: BluePrintValidatorService)
-    : BluePrintCatalogService {
+abstract class BlueprintCatalogServiceImpl(
+        private val bluePrintPathConfiguration: BluePrintPathConfiguration,
+        private val blueprintValidator: BluePrintValidatorService) : BluePrintCatalogService {
 
-    override fun saveToDatabase(blueprintFile: File, validate: Boolean): String {
-        val extractedDirectory: File
-        val archivedDirectory: File
-        val toDeleteDirectory: File
-        val blueprintId = UUID.randomUUID().toString()
+    private val log = LoggerFactory.getLogger(BlueprintCatalogServiceImpl::class.java)!!
+
+    override suspend fun saveToDatabase(processingId: String, blueprintFile: File, validate: Boolean): String {
+
+        var archiveFile: File? = null
+        var workingDir: String? = null
 
         if (blueprintFile.isDirectory) {
-            extractedDirectory = blueprintFile
-            archivedDirectory = File("$blueprintFile.zip")
-            toDeleteDirectory = archivedDirectory
+            log.info("Save processing($processingId) Working Dir(${blueprintFile.absolutePath})")
+            workingDir = blueprintFile.absolutePath
+            archiveFile = normalizedFile(bluePrintPathConfiguration.blueprintArchivePath, processingId, "cba.zip")
 
-            if (!BluePrintArchiveUtils.compress(blueprintFile, archivedDirectory, true)) {
+            if (!BluePrintArchiveUtils.compress(blueprintFile, archiveFile, true)) {
                 throw BluePrintException("Fail to compress blueprint")
             }
         } else {
-            val targetDir = "${blueprintFile.parent}/${BluePrintFileUtils.stripFileExtension(blueprintFile.name)}"
-
-            extractedDirectory = BluePrintArchiveUtils.deCompress(blueprintFile, targetDir)
-            archivedDirectory = blueprintFile
-            toDeleteDirectory = extractedDirectory
+            // Compressed File
+            log.info("Save processing($processingId) CBA(${blueprintFile.absolutePath})")
+            workingDir = normalizedPathName(bluePrintPathConfiguration.blueprintWorkingPath, processingId)
+            archiveFile = blueprintFile
+            // Decompress the CBA file to working Directory
+            blueprintFile.deCompress(workingDir)
         }
 
         var valid = BluePrintConstants.FLAG_N
         if (validate) {
-            blueprintValidator.validateBluePrints(extractedDirectory.path)
+            blueprintValidator.validateBluePrints(workingDir!!)
             valid = BluePrintConstants.FLAG_Y
         }
 
-        val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(blueprintId, extractedDirectory.path)
+        val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(processingId, workingDir!!)
         val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
-        metadata[BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID] = blueprintId
+        metadata[BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID] = processingId
         metadata[BluePrintConstants.PROPERTY_BLUEPRINT_VALID] = valid
 
-        save(metadata, archivedDirectory)
-
-        toDeleteDirectory.deleteRecursively()
+        save(metadata, archiveFile)
 
-        return blueprintId
+        return processingId
     }
 
-    override fun getFromDatabase(name: String, version: String, extract: Boolean): Path = get(name, version, extract)
+    override suspend fun getFromDatabase(name: String, version: String, extract: Boolean): Path = get(name, version,
+            extract)
             ?: throw BluePrintException("Could not find blueprint $name:$version from database")
 
-    override fun deleteFromDatabase(name: String, version: String) = delete(name, version)
+    override suspend fun deleteFromDatabase(name: String, version: String) = delete(name, version)
 
-    abstract fun save(metadata: MutableMap<String, String>, archiveFile: File)
-    abstract fun get(name: String, version: String, extract: Boolean): Path?
-    abstract fun delete(name: String, version: String)
+    abstract suspend fun save(metadata: MutableMap<String, String>, archiveFile: File)
+    abstract suspend fun get(name: String, version: String, extract: Boolean): Path?
+    abstract suspend fun delete(name: String, version: String)
 
 }
\ No newline at end of file
diff --git a/ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/service/load/BluePrintCatalogLoadService.kt b/ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/service/load/BluePrintCatalogLoadService.kt
new file mode 100644 (file)
index 0000000..0ae618f
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.service.load
+
+import com.att.eelf.configuration.EELFManager
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.runBlocking
+import org.apache.commons.lang3.text.StrBuilder
+import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
+import org.springframework.stereotype.Service
+import java.io.File
+import java.util.*
+
+@Service
+open class BluePrintCatalogLoadService(private val bluePrintCatalogService: BluePrintCatalogService) {
+
+    private val log = EELFManager.getInstance().getLogger(BluePrintCatalogLoadService::class.java)
+
+    open fun loadPathsBluePrintModelCatalog(paths: List<String>) {
+        paths.forEach { loadPathBluePrintModelCatalog(it) }
+    }
+
+    open fun loadPathBluePrintModelCatalog(path: String) {
+
+        val files = File(path).listFiles()
+        runBlocking {
+            val errorBuilder = StrBuilder()
+            val deferredResults = mutableListOf<Deferred<Unit>>()
+
+            for (file in files) {
+                deferredResults += async {
+                    loadBluePrintModelCatalog(errorBuilder, file)
+                }
+            }
+
+            for (deferredResult in deferredResults) {
+                deferredResult.await()
+            }
+
+            if (!errorBuilder.isEmpty) {
+                log.error(errorBuilder.toString())
+            }
+        }
+    }
+
+    open suspend fun loadBluePrintModelCatalog(errorBuilder: StrBuilder, file: File) {
+        try {
+            bluePrintCatalogService.saveToDatabase(UUID.randomUUID().toString(), file)
+        } catch (e: Exception) {
+            errorBuilder.appendln("Couldn't load BlueprintModel(${file.name}: ${e.message}")
+        }
+    }
+
+}
\ No newline at end of file
index 8a7c018..790c61e 100644 (file)
@@ -34,7 +34,7 @@ open class ControllerBluePrintCoreConfiguration(private val bluePrintProperties:
     }
 
     @Bean
-    open fun controlelrBlueprintLoadConfiguration(): BluePrintLoadConfiguration {
+    open fun bluePrintLoadConfiguration(): BluePrintLoadConfiguration {
         return bluePrintProperties
                 .propertyBeanType(PREFIX_BLUEPRINT_LOAD_CONFIGURATION, BluePrintLoadConfiguration::class.java)
     }
@@ -53,7 +53,7 @@ open class ControllerBlueprintPropertyConfiguration {
 }
 
 @Service
-open class ControllerBlueprintProperties(var bluePrintPropertyBinder: Binder) {
+open class ControllerBlueprintProperties(private var bluePrintPropertyBinder: Binder) {
     fun <T> propertyBeanType(prefix: String, type: Class<T>): T {
         return bluePrintPropertyBinder.bind(prefix, Bindable.of(type)).get()
     }
index 0ea753f..a214f96 100644 (file)
@@ -26,7 +26,6 @@ import org.springframework.http.MediaType
 import org.springframework.http.ResponseEntity
 import org.springframework.http.codec.multipart.FilePart
 import org.springframework.web.bind.annotation.*
-import reactor.core.publisher.Mono
 
 /**
  * BlueprintModelController Purpose: Handle controllerBlueprint API request
@@ -41,8 +40,8 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint
     @PostMapping("", produces = [MediaType.APPLICATION_JSON_VALUE], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
     @ResponseBody
     @Throws(BluePrintException::class)
-    fun saveBlueprint(@RequestPart("file") file: FilePart): Mono<BlueprintModelSearch> {
-        return bluePrintModelHandler.saveBlueprintModel(file)
+    fun saveBlueprint(@RequestPart("file") filePart: FilePart): BlueprintModelSearch = runBlocking {
+        bluePrintModelHandler.saveBlueprintModel(filePart)
     }
 
     @GetMapping("", produces = [MediaType.APPLICATION_JSON_VALUE])
index 72c27ad..c54bf87 100644 (file)
 
 package org.onap.ccsdk.cds.controllerblueprints.service.handler
 
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
+import org.onap.ccsdk.cds.controllerblueprints.core.*
 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintEnhancerService
-import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
-import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
 import org.onap.ccsdk.cds.controllerblueprints.service.domain.BlueprintModel
 import org.onap.ccsdk.cds.controllerblueprints.service.domain.BlueprintModelSearch
 import org.onap.ccsdk.cds.controllerblueprints.service.repository.ControllerBlueprintModelContentRepository
 import org.onap.ccsdk.cds.controllerblueprints.service.repository.ControllerBlueprintModelRepository
 import org.onap.ccsdk.cds.controllerblueprints.service.repository.ControllerBlueprintModelSearchRepository
 import org.onap.ccsdk.cds.controllerblueprints.service.utils.BluePrintEnhancerUtils
+import org.slf4j.LoggerFactory
 import org.springframework.core.io.ByteArrayResource
 import org.springframework.core.io.Resource
 import org.springframework.http.HttpHeaders
@@ -39,7 +38,6 @@ import org.springframework.http.ResponseEntity
 import org.springframework.http.codec.multipart.FilePart
 import org.springframework.stereotype.Service
 import org.springframework.transaction.annotation.Transactional
-import reactor.core.publisher.Mono
 import java.io.File
 import java.io.IOException
 import java.util.*
@@ -59,6 +57,8 @@ open class BluePrintModelHandler(private val bluePrintCatalogService: BluePrintC
                                  private val blueprintModelContentRepository: ControllerBlueprintModelContentRepository,
                                  private val bluePrintEnhancerService: BluePrintEnhancerService) {
 
+    private val log = LoggerFactory.getLogger(BluePrintModelHandler::class.java)!!
+
     /**
      * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
      *
@@ -76,23 +76,28 @@ open class BluePrintModelHandler(private val bluePrintCatalogService: BluePrintC
      * @throws BluePrintException BluePrintException
     </BlueprintModelSearch> */
     @Throws(BluePrintException::class)
-    open fun saveBlueprintModel(filePart: FilePart): Mono<BlueprintModelSearch> {
+    open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch {
+        val saveId = UUID.randomUUID().toString()
+        val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
         try {
-            val cbaLocation = BluePrintFileUtils.getCbaStorageDirectory(bluePrintLoadConfiguration.blueprintArchivePath)
-            return BluePrintEnhancerUtils.saveCBAFile(filePart, cbaLocation).map { fileName ->
-                var blueprintId: String? = null
-                try {
-                    blueprintId = bluePrintCatalogService.saveToDatabase(cbaLocation.resolve(fileName).toFile(), false)
-                } catch (e: BluePrintException) {
-                    // FIXME handle expection
-                }
-                blueprintModelSearchRepository.findById(blueprintId!!).get()
-            }
+            //Recreate the Dir
+            normalizedFile(bluePrintLoadConfiguration.blueprintArchivePath, saveId).reCreateDirs()
+            val deCompressedFile = normalizedFile(blueprintArchive, "cba.zip")
+            // Copy the File Part to Local File
+            BluePrintEnhancerUtils.copyFromFilePart(filePart, deCompressedFile)
+            // Save the Copied file to Database
+            val blueprintId = bluePrintCatalogService.saveToDatabase(saveId, deCompressedFile, false)
+            // Check and Return the Saved File
+            val blueprintModelSearch = blueprintModelSearchRepository.findById(blueprintId).get()
+            log.info("Save($saveId) successful for blueprint(${blueprintModelSearch.artifactName}) " +
+                    "version(${blueprintModelSearch.artifactVersion})")
+            return blueprintModelSearch
         } catch (e: IOException) {
             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
-                    String.format("I/O Error while uploading the CBA file: %s", e.message), e)
+                    "Error in Save CBA: ${e.message}", e)
+        } finally {
+            deleteDir(blueprintArchive)
         }
-
     }
 
 
@@ -277,20 +282,20 @@ open class BluePrintModelHandler(private val bluePrintCatalogService: BluePrintC
     open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
         val enhanceId = UUID.randomUUID().toString()
         val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
-        val blueprintEnrichmentDir = normalizedPathName(bluePrintLoadConfiguration.blueprintEnrichmentPath, enhanceId)
+        val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
         try {
-            BluePrintEnhancerUtils.decompressFilePart(filePart, blueprintArchive, blueprintEnrichmentDir)
+            BluePrintEnhancerUtils.decompressFilePart(filePart, blueprintArchive, blueprintWorkingDir)
 
             // Enhance the Blue Prints
-            bluePrintEnhancerService.enhance(blueprintEnrichmentDir)
+            bluePrintEnhancerService.enhance(blueprintWorkingDir)
 
-            return BluePrintEnhancerUtils.compressToFilePart(blueprintEnrichmentDir, blueprintArchive)
+            return BluePrintEnhancerUtils.compressToFilePart(blueprintWorkingDir, blueprintArchive)
 
         } catch (e: IOException) {
             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
                     "Error in Enriching CBA: ${e.message}", e)
         } finally {
-            BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintEnrichmentDir)
+            BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
         }
     }
 
@@ -305,12 +310,12 @@ open class BluePrintModelHandler(private val bluePrintCatalogService: BluePrintC
     open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
         val publishId = UUID.randomUUID().toString()
         val blueprintArchive = bluePrintLoadConfiguration.blueprintArchivePath.plus(File.separator).plus(publishId)
-        val blueprintEnrichmentDir = bluePrintLoadConfiguration.blueprintEnrichmentPath.plus(File.separator).plus(publishId)
+        val blueprintWorkingDir = bluePrintLoadConfiguration.blueprintWorkingPath.plus(File.separator).plus(publishId)
         try {
             val compressedFilePart = BluePrintEnhancerUtils
-                    .extractCompressFilePart(filePart, blueprintArchive, blueprintEnrichmentDir)
+                    .extractCompressFilePart(filePart, blueprintArchive, blueprintWorkingDir)
 
-            val blueprintId = bluePrintCatalogService.saveToDatabase(compressedFilePart, true)
+            val blueprintId = bluePrintCatalogService.saveToDatabase(publishId, compressedFilePart, true)
 
             return blueprintModelSearchRepository.findById(blueprintId).get()
 
@@ -318,7 +323,7 @@ open class BluePrintModelHandler(private val bluePrintCatalogService: BluePrintC
             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
                     "Error in Publishing CBA: ${e.message}", e)
         } finally {
-            BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintEnrichmentDir)
+            BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
         }
     }
 
index eca7ce1..2278d80 100644 (file)
@@ -22,6 +22,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogS
 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
 import org.springframework.stereotype.Service
 import java.io.File
+import java.util.*
 
 @Service
 open class BluePrintCatalogLoadService(private val bluePrintCatalogService: BluePrintCatalogService) {
@@ -47,7 +48,7 @@ open class BluePrintCatalogLoadService(private val bluePrintCatalogService: Blue
     open suspend fun loadBluePrintModelCatalog(errorBuilder: MutableList<String>, file: File) {
         try {
             log.info("loading blueprint cba(${file.absolutePath})")
-            bluePrintCatalogService.saveToDatabase(file)
+            bluePrintCatalogService.saveToDatabase(UUID.randomUUID().toString(), file)
         } catch (e: Exception) {
             errorBuilder.add("Couldn't load BlueprintModel(${file.name}: ${e.message}")
         }
index 358a465..3d6e134 100755 (executable)
@@ -23,7 +23,9 @@ import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
 import org.onap.ccsdk.cds.controllerblueprints.core.common.ApplicationConstants
 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
+import org.onap.ccsdk.cds.controllerblueprints.core.deleteDir
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintValidatorService
+import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPath
 import org.onap.ccsdk.cds.controllerblueprints.db.resources.BlueprintCatalogServiceImpl
 import org.onap.ccsdk.cds.controllerblueprints.service.domain.BlueprintModel
 import org.onap.ccsdk.cds.controllerblueprints.service.domain.BlueprintModelContent
@@ -34,7 +36,7 @@ import org.springframework.stereotype.Service
 import java.io.File
 import java.nio.file.Files
 import java.nio.file.Path
-import java.nio.file.Paths
+import java.util.*
 
 /**
  * Similar implementation in [org.onap.ccsdk.cds.blueprintsprocessor.db.BlueprintProcessorCatalogServiceImpl]
@@ -43,7 +45,7 @@ import java.nio.file.Paths
 class ControllerBlueprintCatalogServiceImpl(bluePrintValidatorService: BluePrintValidatorService,
                                             private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
                                             private val blueprintModelRepository: ControllerBlueprintModelRepository)
-    : BlueprintCatalogServiceImpl(bluePrintValidatorService) {
+    : BlueprintCatalogServiceImpl(bluePrintLoadConfiguration, bluePrintValidatorService) {
 
 
     private val log = LoggerFactory.getLogger(ControllerBlueprintCatalogServiceImpl::class.toString())
@@ -52,13 +54,18 @@ class ControllerBlueprintCatalogServiceImpl(bluePrintValidatorService: BluePrint
         log.info("BlueprintProcessorCatalogServiceImpl initialized")
     }
 
-    override fun delete(name: String, version: String) = blueprintModelRepository.deleteByArtifactNameAndArtifactVersion(name, version)
+    override suspend fun delete(name: String, version: String) {
+        // Cleaning Deployed Blueprint
+        deleteDir(bluePrintLoadConfiguration.blueprintDeployPath, name, version)
+        // Cleaning Data Base
+        blueprintModelRepository.deleteByArtifactNameAndArtifactVersion(name, version)
+    }
 
-    override fun get(name: String, version: String, extract: Boolean): Path? {
+    override suspend fun get(name: String, version: String, extract: Boolean): Path? {
         val path = if (extract) {
-            Paths.get("${bluePrintLoadConfiguration.blueprintDeployPath}/$name/$version")
+            normalizedPath(bluePrintLoadConfiguration.blueprintDeployPath, name, version)
         } else {
-            Paths.get("${bluePrintLoadConfiguration.blueprintArchivePath}/$name/$version.zip")
+            normalizedPath(bluePrintLoadConfiguration.blueprintArchivePath, UUID.randomUUID().toString(), "cba.zip")
         }
         blueprintModelRepository.findByArtifactNameAndArtifactVersion(name, version)?.also {
             it.blueprintModelContent.run {
@@ -70,11 +77,14 @@ class ControllerBlueprintCatalogServiceImpl(bluePrintValidatorService: BluePrint
         return null
     }
 
-    override fun save(metadata: MutableMap<String, String>, archiveFile: File) {
+    override suspend fun save(metadata: MutableMap<String, String>, archiveFile: File) {
 
         val artifactName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]
         val artifactVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]
 
+        check(archiveFile.isFile && !archiveFile.isDirectory) {
+            throw BluePrintException("Not a valid Archive file(${archiveFile.absolutePath})")
+        }
 
         blueprintModelRepository.findByArtifactNameAndArtifactVersion(artifactName!!, artifactVersion!!)?.let {
             log.info("Overwriting blueprint model :$artifactName::$artifactVersion")
index 166a2b2..d4753e1 100644 (file)
@@ -84,7 +84,7 @@ class BluePrintEnhancerUtils {
             return artifactType
         }
 
-        private suspend fun copyFromFilePart(filePart: FilePart, targetFile: File): File {
+        suspend fun copyFromFilePart(filePart: FilePart, targetFile: File): File {
             // Delete the Directory
             targetFile.deleteRecursively()
             return filePart.transferTo(targetFile)
index d61e642..64bd3ff 100644 (file)
@@ -17,9 +17,9 @@
 
 package org.onap.ccsdk.cds.controllerblueprints.service.controller
 
-import com.google.gson.Gson
+import kotlinx.coroutines.reactive.awaitSingle
+import kotlinx.coroutines.runBlocking
 import org.json.JSONException
-import org.json.JSONObject
 import org.junit.After
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -27,26 +27,31 @@ import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.onap.ccsdk.cds.controllerblueprints.TestApplication
-import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintArchiveUtils
+import org.onap.ccsdk.cds.controllerblueprints.core.*
+import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintPathConfiguration
+import org.onap.ccsdk.cds.controllerblueprints.service.ControllerBluePrintCoreConfiguration
 import org.onap.ccsdk.cds.controllerblueprints.service.domain.BlueprintModelSearch
+import org.slf4j.LoggerFactory
 import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.beans.factory.annotation.Value
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
 import org.springframework.boot.test.context.SpringBootTest
 import org.springframework.context.annotation.ComponentScan
 import org.springframework.core.io.ByteArrayResource
 import org.springframework.http.HttpMethod
 import org.springframework.http.HttpStatus
+import org.springframework.http.client.MultipartBodyBuilder
 import org.springframework.test.context.ContextConfiguration
 import org.springframework.test.context.junit4.SpringRunner
 import org.springframework.test.web.reactive.server.WebTestClient
+import org.springframework.test.web.reactive.server.returnResult
 import org.springframework.util.Base64Utils
 import org.springframework.web.reactive.function.BodyInserters
 import java.io.File
-import java.io.IOException
 import java.nio.charset.StandardCharsets.UTF_8
-import java.nio.file.Files
 import java.nio.file.Paths
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
 
 /**
  * BlueprintModelControllerTest Purpose: Integration test at API level
@@ -57,109 +62,142 @@ import java.nio.file.Paths
 
 @RunWith(SpringRunner::class)
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@ContextConfiguration(classes = [TestApplication::class])
+@ContextConfiguration(classes = [TestApplication::class, ControllerBluePrintCoreConfiguration::class])
 @ComponentScan(basePackages = ["org.onap.ccsdk.cds.controllerblueprints"])
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @EnableAutoConfiguration
 class BlueprintModelControllerTest {
 
-    companion object {
+    private val log = LoggerFactory.getLogger(BlueprintModelControllerTest::class.java)!!
 
-        private var id: String? = null
-        private var name: String? = null
-        private var version: String? = null
-        private var tag: String? = null
-        private var result: String? = null
+    companion object {
+        private var bp: BlueprintModelSearch? = null
     }
 
-    @Value("\${controllerblueprints.loadBluePrintPaths}")
-    private val loadBluePrintPaths: String? = null
-
     @Autowired
-    private val webTestClient: WebTestClient? = null
+    lateinit var webTestClient: WebTestClient
+
+    private var bluePrintLoadConfiguration: BluePrintPathConfiguration? = null
 
-    @Value("\${controllerblueprints.loadBlueprintsExamplesPath}")
-    private val blueprintArchivePath: String? = null
+    private val blueprintDir = "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration"
+    private var zipBlueprintFileName: String? = null
+
+    private var testZipFile: File? = null
 
-    private val filename = "test.zip"
-    private var blueprintFile: File? = null
-    private var zipBlueprintFile: File? = null
 
     @Before
-    @Throws(Exception::class)
     fun setUp() {
-        blueprintFile = File(loadBluePrintPaths+"/baseconfiguration")
-        if (blueprintFile!!.isDirectory) {
-            zipBlueprintFile = File(Paths.get(blueprintArchivePath).resolve(filename).toString())
-            BluePrintArchiveUtils.compress(blueprintFile!!, zipBlueprintFile!!, true)
+        assertNotNull(webTestClient, " Failed to create WebTestClient")
+
+        bluePrintLoadConfiguration = BluePrintPathConfiguration().apply {
+            blueprintArchivePath = "./target/blueprints/archive"
+            blueprintWorkingPath = "./target/blueprints/work"
+            blueprintDeployPath = "./target/blueprints/deploy"
         }
+        zipBlueprintFileName = normalizedPathName(bluePrintLoadConfiguration!!.blueprintArchivePath, "test.zip")
+
+        val archiveDir = normalizedFile(bluePrintLoadConfiguration!!.blueprintArchivePath).reCreateDirs()
+        assertTrue(archiveDir.exists(), "failed to create archiveDir(${archiveDir.absolutePath}")
+
+        val blueprintFile = Paths.get(blueprintDir).toFile().normalize()
+        testZipFile = blueprintFile.compress(zipBlueprintFileName!!)
+        assertNotNull(testZipFile, "test zip is null")
+        assertTrue(testZipFile!!.exists(), "Failed to create blueprint test zip(${testZipFile!!.absolutePath}")
     }
 
     @After
-    @Throws(Exception::class)
     fun tearDown() {
-        zipBlueprintFile!!.delete()
+        deleteDir(bluePrintLoadConfiguration!!.blueprintArchivePath)
+        deleteDir(bluePrintLoadConfiguration!!.blueprintWorkingPath)
     }
 
     @Test
-    @Throws(IOException::class, JSONException::class)
-    fun test1_saveBluePrint() {
-        webTestClient(HttpMethod.POST,
-                BodyInserters.fromMultipartData("file", object : ByteArrayResource(Files.readAllBytes(zipBlueprintFile!!.toPath())) {
-                    override fun getFilename(): String? {
+    fun test01_saveBluePrint() {
+        bp = runBlocking {
+            val body = MultipartBodyBuilder().apply {
+                part("file", object : ByteArrayResource(testZipFile!!.readBytes()) {
+                    override fun getFilename(): String {
                         return "test.zip"
                     }
-                }),
-                "/api/v1/blueprint-model",
-                HttpStatus.OK, true)
+                })
+            }.build()
+
+            val saveBP = webTestClient
+                    .post()
+                    .uri("/api/v1/blueprint-model")
+                    .body(BodyInserters.fromMultipartData(body))
+                    .exchange()
+                    .expectStatus().isOk
+                    .returnResult<BlueprintModelSearch>()
+                    .responseBody
+                    .awaitSingle()
+
+            assertNotNull(saveBP, "failed to get response")
+            assertEquals("baseconfiguration", saveBP.artifactName, "mismatch artifact name")
+            assertEquals("1.0.0", saveBP.artifactVersion, "mismatch artifact version")
+            assertEquals("N", saveBP.published, "mismatch publish")
+            saveBP
+        }
     }
 
     @Test
     @Throws(JSONException::class)
-    fun test2_getBluePrintByNameAndVersion() {
-        webTestClient(HttpMethod.GET, null, "/api/v1/blueprint-model/by-name/$name/version/$version", HttpStatus.OK, false)
+    fun test02_getBluePrintByNameAndVersion() {
+        webTestClient(HttpMethod.GET, null,
+                "/api/v1/blueprint-model/by-name/${bp!!.artifactName}/version/${bp!!.artifactVersion}",
+                HttpStatus.OK, false)
     }
 
 
     @Test
     @Throws(JSONException::class)
-    fun test3_getBlueprintModel() {
-        webTestClient(HttpMethod.GET, null, "/api/v1/blueprint-model/$id", HttpStatus.OK, false)
+    fun test03_getBlueprintModel() {
+        webTestClient(HttpMethod.GET, null,
+                "/api/v1/blueprint-model/${bp!!.id}",
+                HttpStatus.OK, false)
     }
 
     @Test
     @Throws(JSONException::class)
-    fun test4_getAllBlueprintModel() {
+    fun test04_getAllBlueprintModel() {
         webTestClient(HttpMethod.GET, null, "/api/v1/blueprint-model", HttpStatus.OK, false)
     }
 
     @Test
     @Throws(JSONException::class)
-    fun test5_downloadBluePrint() {
-        webTestClient(HttpMethod.GET, null, "/api/v1/blueprint-model/download/$id", HttpStatus.OK, false)
+    fun test05_downloadBluePrint() {
+        webTestClient(HttpMethod.GET, null,
+                "/api/v1/blueprint-model/download/${bp!!.id}",
+                HttpStatus.OK, false)
+    }
+
+    @Test
+    fun test06_enrichBlueprintModel() {
     }
 
     @Test
-    fun test6_publishBlueprintModel() {
+    fun test07_publishBlueprintModel() {
     }
 
     @Test
     @Throws(JSONException::class)
-    fun test7_searchBlueprintModels() {
-        webTestClient(HttpMethod.GET, null, "/api/v1/blueprint-model/search/$name", HttpStatus.OK, false)
+    fun test08_searchBlueprintModels() {
+        webTestClient(HttpMethod.GET, null,
+                "/api/v1/blueprint-model/search/${bp!!.artifactName}",
+                HttpStatus.OK, false)
     }
 
     @Test
     @Throws(JSONException::class)
-    fun test8_downloadBlueprintByNameAndVersion() {
-        webTestClient(HttpMethod.GET, null, "/api/v1/blueprint-model/download/by-name/$name/version/$version", HttpStatus.OK, false)
+    fun test09_downloadBlueprintByNameAndVersion() {
+        webTestClient(HttpMethod.GET, null,
+                "/api/v1/blueprint-model/download/by-name/${bp!!.artifactName}/version/${bp!!.artifactVersion}",
+                HttpStatus.OK, false)
     }
 
     @Test
-    fun test9_deleteBluePrint() {
-        //TODO: Use webTestClient function
-        //webTestClient(HttpMethod.DELETE, null, "/api/v1/blueprint-model/" + id, HttpStatus.OK, false);
-        webTestClient!!.delete().uri("/api/v1/blueprint-model/$id")
+    fun test10_deleteBluePrint() {
+        webTestClient.delete().uri("/api/v1/blueprint-model/${bp!!.id}")
                 .header("Authorization", "Basic " + Base64Utils
                         .encodeToString(("ccsdkapps" + ":" + "ccsdkapps").toByteArray(UTF_8)))
                 .exchange()
@@ -167,27 +205,20 @@ class BlueprintModelControllerTest {
     }
 
     @Throws(JSONException::class)
-    private fun webTestClient(requestMethod: HttpMethod, body: BodyInserters.MultipartInserter?, uri: String, expectedResponceStatus: HttpStatus, setParam: Boolean) {
+    private fun webTestClient(requestMethod: HttpMethod, body: BodyInserters.MultipartInserter?, uri: String,
+                              expectedResponceStatus: HttpStatus, setParam: Boolean) {
 
-        result = String(webTestClient!!.method(requestMethod).uri(uri)
+        log.info("Requesting($uri): Method(${requestMethod.name})")
+
+        webTestClient.method(requestMethod).uri(uri)
                 .header("Authorization", "Basic " + Base64Utils
                         .encodeToString(("ccsdkapps" + ":" + "ccsdkapps").toByteArray(UTF_8)))
                 .body(body)
                 .exchange()
                 .expectStatus().isEqualTo(expectedResponceStatus)
                 .expectBody()
-                .returnResult().responseBody!!)
-
-        if (setParam) {
-            val jsonResponse = JSONObject(result)
-            val blueprintModelSearchJSON = jsonResponse.getJSONObject("blueprintModel")
-            val gson = Gson()
-            val blueprintModelSearch = gson.fromJson(blueprintModelSearchJSON.toString(), BlueprintModelSearch::class.java)
-            id = blueprintModelSearch.id
-            name = blueprintModelSearch.artifactName
-            version = blueprintModelSearch.artifactVersion
-            tag = blueprintModelSearch.tags
-        }
+                .returnResult().responseBody!!
+
     }
 
 }
\ No newline at end of file
index 011bad3..19430ad 100755 (executable)
@@ -24,7 +24,7 @@ resourceSourceMappings=processor-db=source-processor-db,input=source-input,defau
 # Controller Blueprints Core Configuration
 controllerblueprints.blueprintDeployPath=./target/blueprints/deploy
 controllerblueprints.blueprintArchivePath=./target/blueprints/archive
-controllerblueprints.blueprintEnrichmentPath=./target/blueprints/enrichment
+controllerblueprints.blueprintWorkingPath=./target/blueprints/work
 # Controller Blueprint Load Configurations
 controllerblueprints.loadInitialData=false
 controllerblueprints.loadBluePrint=false