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