Append input param true in workflow-spec
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / inbounds / designer-api / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / designer / api / handler / BluePrintModelHandler.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2019 Bell Canada.
4  * Modifications Copyright © 2019 IBM.
5  * Modifications Copyright © 2019 Orange.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 package org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler
21
22 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModel
23 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModelSearch
24 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.repository.BlueprintModelContentRepository
25 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.repository.BlueprintModelRepository
26 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.repository.BlueprintModelSearchRepository
27 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.DesignerApiDomains
28 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.BootstrapRequest
29 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.WorkFlowSpecRequest
30 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.WorkFlowSpecResponse
31 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.WorkFlowData
32 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.WorkFlowsResponse
33 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.load.BluePrintDatabaseLoadService
34 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.utils.BluePrintEnhancerUtils
35 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
36 import org.onap.ccsdk.cds.controllerblueprints.core.logger
37 import org.onap.ccsdk.cds.controllerblueprints.core.httpProcessorException
38 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
39 import org.onap.ccsdk.cds.controllerblueprints.core.updateErrorMessage
40 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
41 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
42 import org.onap.ccsdk.cds.controllerblueprints.core.deleteNBDir
43 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
44 import org.onap.ccsdk.cds.controllerblueprints.core.data.DataType
45 import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition
46 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
47 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintEnhancerService
48 import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintCompileCache
49 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
50 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
51 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
52 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
53 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
54 import org.onap.ccsdk.cds.error.catalog.core.ErrorCatalogCodes
55 import org.onap.ccsdk.cds.error.catalog.core.utils.errorCauseOrDefault
56 import org.onap.ccsdk.cds.error.catalog.core.utils.errorMessageOrDefault
57 import org.springframework.core.io.ByteArrayResource
58 import org.springframework.core.io.Resource
59 import org.springframework.data.domain.Page
60 import org.springframework.data.domain.PageRequest
61 import org.springframework.data.domain.Pageable
62 import org.springframework.http.HttpHeaders
63 import org.springframework.http.MediaType
64 import org.springframework.http.ResponseEntity
65 import org.springframework.http.codec.multipart.FilePart
66 import org.springframework.stereotype.Service
67 import org.springframework.transaction.annotation.Transactional
68 import java.io.File
69 import java.io.IOException
70 import java.util.UUID
71
72 /**
73  * BlueprintModelHandler Purpose: Handler service to handle the request from BlurPrintModelRest
74  *
75  * @author Brinda Santh
76  * @version 1.0
77  */
78
79 @Service
80 open class BluePrintModelHandler(
81     private val bluePrintDatabaseLoadService: BluePrintDatabaseLoadService,
82     private val blueprintsProcessorCatalogService: BluePrintCatalogService,
83     private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
84     private val blueprintModelSearchRepository: BlueprintModelSearchRepository,
85     private val blueprintModelRepository: BlueprintModelRepository,
86     private val blueprintModelContentRepository: BlueprintModelContentRepository,
87     private val bluePrintEnhancerService: BluePrintEnhancerService
88 ) {
89
90     private val log = logger(BluePrintModelHandler::class)
91
92     open suspend fun bootstrapBlueprint(bootstrapRequest: BootstrapRequest) {
93         log.info(
94             "Bootstrap request with type load(${bootstrapRequest.loadModelType}), " +
95                     "resource dictionary load(${bootstrapRequest.loadResourceDictionary}) and " +
96                     "cba load(${bootstrapRequest.loadCBA})"
97         )
98         if (bootstrapRequest.loadModelType) {
99             bluePrintDatabaseLoadService.initModelTypes()
100         }
101         if (bootstrapRequest.loadResourceDictionary) {
102             bluePrintDatabaseLoadService.initResourceDictionary()
103         }
104         if (bootstrapRequest.loadCBA) {
105             bluePrintDatabaseLoadService.initBluePrintCatalog()
106         }
107     }
108
109     @Throws(BluePrintException::class)
110     open suspend fun prepareWorkFlowSpec(req: WorkFlowSpecRequest):
111             WorkFlowSpecResponse {
112         val basePath = blueprintsProcessorCatalogService.getFromDatabase(req
113                 .blueprintName, req.version)
114         log.info("blueprint base path $basePath")
115
116         val blueprintContext = BluePrintMetadataUtils.getBluePrintContext(basePath.toString())
117         val workFlow = blueprintContext.workflowByName(req.workflowName)
118
119         val wfRes = WorkFlowSpecResponse()
120         wfRes.blueprintName = req.blueprintName
121         wfRes.version = req.version
122
123         val workFlowData = WorkFlowData()
124         workFlowData.workFlowName = req.workflowName
125         workFlowData.inputs = workFlow.inputs
126         workFlowData.outputs = workFlow.outputs
127         wfRes.workFlowData = workFlowData
128
129         if (workFlow.inputs != null) {
130             for ((k, v) in workFlow.inputs!!) {
131                 addPropertyInfo(k, v, blueprintContext, wfRes)
132             }
133         }
134
135         if (workFlow.outputs != null) {
136             for ((k, v) in workFlow.outputs!!) {
137                 addPropertyInfo(k, v, blueprintContext, wfRes)
138             }
139         }
140
141         return wfRes
142     }
143
144     private fun addPropertyInfo(propName: String, prop: PropertyDefinition, ctx: BluePrintContext, res: WorkFlowSpecResponse) {
145         updatePropertyInfo(propName, prop, ctx, res)
146         addDataType(prop.type, ctx, res)
147         if (prop.entrySchema != null && prop.entrySchema!!.type != null) {
148             addDataType(prop.entrySchema!!.type, ctx, res)
149         }
150     }
151
152     private fun updatePropertyInfo(name: String, prop: PropertyDefinition, ctx: BluePrintContext, res: WorkFlowSpecResponse) {
153         if (prop.inputparam == null || prop.inputparam == false) {
154             var workflow = ctx.workflowByName(res.workFlowData.workFlowName)
155             for ((k, v) in workflow.steps!!) {
156                 var arts = ctx.nodeTemplateArtifacts(v.target!!)
157                 if (arts != null) {
158                     for ((k, v) in arts.entries!!) {
159                         if (v.type == "artifact-mapping-resource") {
160                             val file: String = v.file
161                             val completePath = ctx.rootPath.plus(File.separator).plus(file)
162                             val resourceAssignment = JacksonUtils.getListFromFile(completePath, ResourceAssignment::class.java)
163                             for (res in resourceAssignment) {
164                                 if (res.name == name && res.inputParameter) {
165                                     prop.inputparam = true
166                                     return
167                                 }
168                             }
169                         }
170                     }
171                 }
172             }
173         }
174     }
175     private fun addDataType(name: String, ctx: BluePrintContext, res: WorkFlowSpecResponse) {
176         var data = ctx.dataTypeByName(name)
177         if (data != null) {
178             res.dataTypes?.put(name, data)
179             addParentDataType(data, ctx, res)
180         }
181     }
182
183     private fun addParentDataType(data: DataType, ctx: BluePrintContext, res: WorkFlowSpecResponse) {
184         if (data.properties != null) {
185             for ((k, v) in data.properties!!) {
186                 addPropertyInfo(k, v, ctx, res)
187             }
188         }
189     }
190
191     @Throws(BluePrintException::class)
192     open suspend fun getWorkflowNames(name: String, version: String): WorkFlowsResponse {
193         val basePath = blueprintsProcessorCatalogService.getFromDatabase(
194                 name, version)
195         log.info("blueprint base path $basePath")
196
197         var res = WorkFlowsResponse()
198         res.blueprintName = name
199         res.version = version
200
201         val blueprintContext = BluePrintMetadataUtils.getBluePrintContext(
202                 basePath.toString())
203         if (blueprintContext.workflows() != null) {
204             res.workflows = blueprintContext.workflows()!!.keys
205         }
206         return res
207     }
208
209     /**
210      * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
211      *
212      * @return List<BlueprintModelSearch> list of the controller blueprint archives
213     </BlueprintModelSearch> */
214     open fun allBlueprintModel(): List<BlueprintModelSearch> {
215         return blueprintModelSearchRepository.findAll()
216     }
217
218     /**
219      * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
220      *
221      * @return List<BlueprintModelSearch> list of the controller blueprint archives
222     </BlueprintModelSearch> */
223     open fun allBlueprintModel(pageRequest: Pageable): Page<BlueprintModelSearch> {
224         return blueprintModelSearchRepository.findAll(pageRequest)
225     }
226
227     /**
228      * This is a saveBlueprintModel method
229      *
230      * @param filePart filePart
231      * @return Mono<BlueprintModelSearch>
232      * @throws BluePrintException BluePrintException
233     </BlueprintModelSearch> */
234     @Throws(BluePrintException::class)
235     open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch {
236         try {
237             return upload(filePart, false)
238         } catch (e: IOException) {
239             throw httpProcessorException(ErrorCatalogCodes.IO_FILE_INTERRUPT, DesignerApiDomains.DESIGNER_API,
240                     "Error in Save CBA: ${e.message}", e.errorCauseOrDefault())
241         }
242     }
243
244     /**
245      * This is a searchBlueprintModels method
246      *
247      * @param tags tags
248      * @return List<BlueprintModelSearch>
249     </BlueprintModelSearch> */
250     open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
251         return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
252     }
253
254     /**
255      * This is a getBlueprintModelSearchByNameAndVersion method
256      *
257      * @param name name
258      * @param version version
259      * @return BlueprintModelSearch
260      * @throws BluePrintException BluePrintException
261      */
262     @Throws(BluePrintException::class)
263     open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch? {
264         return blueprintModelSearchRepository.findByArtifactNameAndArtifactVersion(name, version)
265             /*?: throw BluePrintException(
266                 ErrorCode.RESOURCE_NOT_FOUND.value,
267                 String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
268             )*/
269     }
270
271     /**
272      * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
273      *
274      * @param name name
275      * @param version version
276      * @return ResponseEntity<Resource>
277      * @throws BluePrintException BluePrintException
278     </Resource> */
279     @Throws(BluePrintException::class)
280     open fun downloadBlueprintModelFileByNameAndVersion(
281         name: String,
282         version: String
283     ): ResponseEntity<Resource> {
284         try {
285             val archiveByteArray = download(name, version)
286             val fileName = "${name}_$version.zip"
287             return prepareResourceEntity(fileName, archiveByteArray)
288         } catch (e: BluePrintProcessorException) {
289             e.http(ErrorCatalogCodes.RESOURCE_NOT_FOUND)
290             val errorMsg = "Error while downloading the CBA file by Blueprint Name ($name) and Version ($version)."
291             throw e.updateErrorMessage(DesignerApiDomains.DESIGNER_API, errorMsg,
292                     "Wrong resource definition or resolution failed.")
293         }
294     }
295
296     /**
297      * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
298      *
299      * @return ResponseEntity<Resource>
300      * @throws BluePrintException BluePrintException
301     </Resource> */
302     @Throws(BluePrintException::class)
303     open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
304         val blueprintModel: BlueprintModel
305         try {
306             blueprintModel = getBlueprintModel(id)
307         } catch (e: BluePrintException) {
308             throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, DesignerApiDomains.DESIGNER_API,
309                     "Error while downloading the CBA file: couldn't get blueprint modelby ID ($id)",
310                     e.errorCauseOrDefault())
311         }
312
313         val fileName = "${blueprintModel.artifactName}_${blueprintModel.artifactVersion}.zip"
314         val file = blueprintModel.blueprintModelContent?.content
315             ?: throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, DesignerApiDomains.DESIGNER_API,
316                     "Error while downloading the CBA file: couldn't get model content")
317         return prepareResourceEntity(fileName, file)
318     }
319
320     /**
321      * @return ResponseEntity<Resource>
322     </Resource> */
323     private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
324         return ResponseEntity.ok()
325             .contentType(MediaType.parseMediaType("text/plain"))
326             .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
327             .body(ByteArrayResource(file))
328     }
329
330     /**
331      * This is a getBlueprintModel method
332      *
333      * @param id id
334      * @return BlueprintModel
335      * @throws BluePrintException BluePrintException
336      */
337     @Throws(BluePrintException::class)
338     open fun getBlueprintModel(id: String): BlueprintModel {
339         val blueprintModel: BlueprintModel
340         val dbBlueprintModel = blueprintModelRepository.findById(id)
341         if (dbBlueprintModel.isPresent) {
342             blueprintModel = dbBlueprintModel.get()
343         } else {
344             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
345             throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, DesignerApiDomains.DESIGNER_API, msg)
346         }
347         return blueprintModel
348     }
349
350     /**
351      * This is a getBlueprintModelByNameAndVersion method
352      *
353      * @param name name
354      * @param version version
355      * @return BlueprintModel
356      * @throws BluePrintException BluePrintException
357      */
358     @Throws(BluePrintException::class)
359     open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
360         val blueprintModel = blueprintModelRepository
361             .findByArtifactNameAndArtifactVersion(name, version)
362         if (blueprintModel != null) {
363             return blueprintModel
364         } else {
365             val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
366             throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, DesignerApiDomains.DESIGNER_API, msg)
367         }
368     }
369
370     /**
371      * This is a getBlueprintModelSearch method
372      *
373      * @param id id
374      * @return BlueprintModelSearch
375      * @throws BluePrintException BluePrintException
376      */
377     @Throws(BluePrintException::class)
378     open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
379         return blueprintModelSearchRepository.findById(id)
380             ?: throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, DesignerApiDomains.DESIGNER_API,
381                     String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id))
382     }
383
384     /**
385      * This is a searchBluePrintModelsByKeyWord method to retrieve specific  BlueprintModel in Database
386      * where keyword equals updatedBy or tags or artifcat name or artifcat version or artifact type
387      * @author Shaaban Ebrahim
388      * @param keyWord
389      *
390      * @return List<BlueprintModelSearch> list of the controller blueprint
391     </BlueprintModelSearch> */
392     open fun searchBluePrintModelsByKeyWord(keyWord: String): List<BlueprintModelSearch> {
393         return blueprintModelSearchRepository.findByUpdatedByOrTagsOrOrArtifactNameOrOrArtifactVersionOrArtifactType(
394             keyWord, keyWord, keyWord, keyWord, keyWord
395         )
396     }
397
398     /**
399      * This is a searchBluePrintModelsByKeyWordPagebale method to retrieve specific  BlueprintModel in Database
400      * where keyword equals updatedBy or tags or artifcat name or artifcat version or artifact type and pageable
401      * @author Shaaban Ebrahim
402      * @param keyWord
403      *
404      * @return List<BlueprintModelSearch> list of the controller blueprint
405     </BlueprintModelSearch> */
406     open fun searchBluePrintModelsByKeyWordPaged(keyWord: String, pageRequest: PageRequest): Page<BlueprintModelSearch> {
407         return blueprintModelSearchRepository.findByUpdatedByContainingIgnoreCaseOrTagsContainingIgnoreCaseOrArtifactNameContainingIgnoreCaseOrArtifactVersionContainingIgnoreCaseOrArtifactTypeContainingIgnoreCase(
408             keyWord,
409             keyWord,
410             keyWord,
411             keyWord,
412             keyWord,
413             pageRequest
414         )
415     }
416
417     /**
418      * This is a deleteBlueprintModel method
419      *
420      * @param id id
421      * @throws BluePrintException BluePrintException
422      */
423     @Transactional
424     @Throws(BluePrintException::class)
425     open fun deleteBlueprintModel(id: String) {
426         val dbBlueprintModel = blueprintModelRepository.findById(id)
427         if (dbBlueprintModel.isPresent) {
428             blueprintModelContentRepository.deleteByBlueprintModel(dbBlueprintModel.get())
429             blueprintModelRepository.delete(dbBlueprintModel.get())
430         } else {
431             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
432             throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, DesignerApiDomains.DESIGNER_API, msg)
433         }
434     }
435
436     open suspend fun deleteBlueprintModel(name: String, version: String) {
437         blueprintsProcessorCatalogService.deleteFromDatabase(name, version)
438     }
439
440     /**
441      * This is a CBA enrichBlueprint method
442      * Save the Zip File in archive location and extract the cba content.
443      * Populate the Enhancement Location
444      * Enhance the CBA content
445      * Compress the Enhanced Content
446      * Return back the the compressed content back to the caller.
447      *
448      * @param filePart filePart
449      * @return ResponseEntity<Resource>
450      * @throws BluePrintException BluePrintException
451      */
452     @Throws(BluePrintException::class)
453     open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
454         try {
455             val enhancedByteArray = enrichBlueprintFileSource(filePart)
456             return BluePrintEnhancerUtils.prepareResourceEntity("enhanced-cba.zip", enhancedByteArray)
457         } catch (e: BluePrintProcessorException) {
458             e.http(ErrorCatalogCodes.IO_FILE_INTERRUPT)
459             val errorMsg = "Error while enhancing the CBA package."
460             throw e.updateErrorMessage(DesignerApiDomains.DESIGNER_API, errorMsg,
461                     "Wrong CBA file provided, please verify and enrich Again.")
462         } catch (e: Exception) {
463             throw httpProcessorException(ErrorCatalogCodes.IO_FILE_INTERRUPT, DesignerApiDomains.DESIGNER_API,
464                     "EnrichBlueprint: ${e.message}", e.errorCauseOrDefault())
465         }
466     }
467
468     /**
469      * This is a publishBlueprintModel method to change the status published to YES
470      * NOTE: this method is meant for enriched blueprints only.
471      *
472      * @param filePart filePart
473      * @return BlueprintModelSearch
474      * @throws BluePrintException BluePrintException
475      */
476     @Throws(BluePrintException::class)
477     open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
478         try {
479             return upload(filePart, true)
480         } catch (e: BluePrintProcessorException) {
481             e.http(ErrorCatalogCodes.IO_FILE_INTERRUPT)
482             val errorMsg = "Error in Publishing CBA."
483             throw e.updateErrorMessage(DesignerApiDomains.DESIGNER_API, errorMsg,
484                     "Wrong CBA provided, please verify and enrich your CBA.")
485         } catch (e: Exception) {
486             throw httpProcessorException(ErrorCatalogCodes.IO_FILE_INTERRUPT, DesignerApiDomains.DESIGNER_API,
487                     "Error in Publishing CBA: ${e.message}", e.errorCauseOrDefault())
488         }
489     }
490
491     /**
492      * Enrich and publish the blueprint.
493      * NOTE: this method is meant for the unenriched vs publishBlueprint(filePart)
494      *       which is used for enriched blueprints.
495      *
496      * @param filePart filePart
497      * @return BlueprintModelSearch
498      * @throws BluePrintException BluePrintException
499      */
500     @Throws(BluePrintException::class)
501     open suspend fun enrichAndPublishBlueprint(filePart: FilePart): BlueprintModelSearch {
502         try {
503             val enhancedByteArray = enrichBlueprintFileSource(filePart)
504             return upload(enhancedByteArray, true)
505         } catch (e: BluePrintProcessorException) {
506             e.http(ErrorCatalogCodes.IO_FILE_INTERRUPT)
507             val errorMsg = "Error while enhancing and uploading the CBA package."
508             throw e.updateErrorMessage(DesignerApiDomains.DESIGNER_API, errorMsg,
509                 "Wrong CBA file provided, please verify the source CBA.")
510         } catch (e: Exception) {
511             throw httpProcessorException(ErrorCatalogCodes.IO_FILE_INTERRUPT, DesignerApiDomains.DESIGNER_API,
512                 "EnrichBlueprint: ${e.message}", e.errorCauseOrDefault())
513         }
514     }
515
516     /** Common CBA Save and Publish function for RestController and GRPC Handler, the [fileSource] may be
517      * byteArray or File Part type.*/
518     open suspend fun upload(fileSource: Any, validate: Boolean): BlueprintModelSearch {
519         val saveId = UUID.randomUUID().toString()
520         val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
521         val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId)
522         try {
523             val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
524             when (fileSource) {
525                 is FilePart -> BluePrintEnhancerUtils.filePartAsFile(fileSource, compressedFile)
526                 is ByteArray -> BluePrintEnhancerUtils.byteArrayAsFile(fileSource, compressedFile)
527             }
528             // Save the Copied file to Database
529             val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate)
530
531             return blueprintModelSearchRepository.findById(blueprintId)
532                 ?: throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, DesignerApiDomains.DESIGNER_API,
533                         String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
534         } catch (e: BluePrintException) {
535             e.http(ErrorCatalogCodes.IO_FILE_INTERRUPT)
536             val errorMsg = "Error in Upload CBA."
537             throw e.updateErrorMessage(DesignerApiDomains.DESIGNER_API, errorMsg,
538                     "Wrong enriched CBA.")
539         } catch (e: IOException) {
540             throw httpProcessorException(ErrorCatalogCodes.IO_FILE_INTERRUPT, DesignerApiDomains.DESIGNER_API,
541                     "Error in Upload CBA: ${e.errorMessageOrDefault()}", e.errorCauseOrDefault())
542         } finally {
543             // Clean blueprint script cache
544             val cacheKey = BluePrintFileUtils
545                 .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId))
546             BluePrintCompileCache.cleanClassLoader(cacheKey)
547             deleteNBDir(blueprintArchive)
548             deleteNBDir(blueprintWorking)
549         }
550     }
551
552     /** Common CBA download function for RestController and GRPC Handler, the [fileSource] may be
553      * byteArray or File Part type.*/
554     open fun download(name: String, version: String): ByteArray {
555         try {
556             val blueprintModel = getBlueprintModelByNameAndVersion(name, version)
557             return blueprintModel.blueprintModelContent?.content
558                 ?: throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, DesignerApiDomains.DESIGNER_API,
559                         "Error while downloading the CBA file: couldn't get model content")
560         } catch (e: BluePrintException) {
561             e.http(ErrorCatalogCodes.RESOURCE_NOT_FOUND)
562             val errorMsg = "Fail to get Blueprint Model content."
563             throw e.updateErrorMessage(DesignerApiDomains.DESIGNER_API, errorMsg,
564                     "Wrong name and version was provide.")
565         }
566     }
567
568     /** Common CBA Enrich function for RestController and GRPC Handler, the [fileSource] may be
569      * byteArray or File Part type.*/
570     open suspend fun enrichBlueprintFileSource(fileSource: Any): ByteArray {
571         val enhanceId = UUID.randomUUID().toString()
572         val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
573         val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
574         try {
575             when (fileSource) {
576                 is FilePart -> BluePrintEnhancerUtils
577                     .copyFilePartToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
578                 is ByteArray -> BluePrintEnhancerUtils
579                     .copyByteArrayToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
580             } // Enhance the Blue Prints
581             bluePrintEnhancerService.enhance(blueprintWorkingDir)
582
583             return BluePrintEnhancerUtils.compressEnhanceDirAndReturnByteArray(blueprintWorkingDir, blueprintArchive)
584         } catch (e: BluePrintException) {
585             e.http(ErrorCatalogCodes.IO_FILE_INTERRUPT)
586             val errorMsg = "Fail Enriching the CBA."
587             throw e.updateErrorMessage(DesignerApiDomains.DESIGNER_API, errorMsg)
588         } catch (e: IOException) {
589             throw httpProcessorException(ErrorCatalogCodes.IO_FILE_INTERRUPT, DesignerApiDomains.DESIGNER_API,
590                     "Error while Enriching the CBA file.", e.errorCauseOrDefault())
591         } finally {
592             BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
593         }
594     }
595
596     companion object {
597
598         private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
599         private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"
600     }
601 }