2 * Copyright © 2017-2018 AT&T Intellectual Property.
3 * Modifications Copyright © 2019 Bell Canada.
4 * Modifications Copyright © 2019 IBM.
5 * Modifications Copyright © 2019 Orange.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 package org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler
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.BootstrapRequest
28 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.load.BluePrintDatabaseLoadService
29 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.utils.BluePrintEnhancerUtils
30 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
31 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
32 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
33 import org.onap.ccsdk.cds.controllerblueprints.core.deleteNBDir
34 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
35 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintEnhancerService
36 import org.onap.ccsdk.cds.controllerblueprints.core.logger
37 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
38 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
39 import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintCompileCache
40 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
41 import org.springframework.core.io.ByteArrayResource
42 import org.springframework.core.io.Resource
43 import org.springframework.data.domain.Page
44 import org.springframework.data.domain.PageRequest
45 import org.springframework.data.domain.Pageable
46 import org.springframework.http.HttpHeaders
47 import org.springframework.http.MediaType
48 import org.springframework.http.ResponseEntity
49 import org.springframework.http.codec.multipart.FilePart
50 import org.springframework.stereotype.Service
51 import org.springframework.transaction.annotation.Transactional
52 import java.io.IOException
56 * BlueprintModelHandler Purpose: Handler service to handle the request from BlurPrintModelRest
58 * @author Brinda Santh
63 open class BluePrintModelHandler(
64 private val bluePrintDatabaseLoadService: BluePrintDatabaseLoadService,
65 private val blueprintsProcessorCatalogService: BluePrintCatalogService,
66 private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
67 private val blueprintModelSearchRepository: BlueprintModelSearchRepository,
68 private val blueprintModelRepository: BlueprintModelRepository,
69 private val blueprintModelContentRepository: BlueprintModelContentRepository,
70 private val bluePrintEnhancerService: BluePrintEnhancerService
73 private val log = logger(BluePrintModelHandler::class)
75 open suspend fun bootstrapBlueprint(bootstrapRequest: BootstrapRequest) {
77 "Bootstrap request with type load(${bootstrapRequest.loadModelType}), " +
78 "resource dictionary load(${bootstrapRequest.loadResourceDictionary}) and " +
79 "cba load(${bootstrapRequest.loadCBA})"
81 if (bootstrapRequest.loadModelType) {
82 bluePrintDatabaseLoadService.initModelTypes()
84 if (bootstrapRequest.loadResourceDictionary) {
85 bluePrintDatabaseLoadService.initResourceDictionary()
87 if (bootstrapRequest.loadCBA) {
88 bluePrintDatabaseLoadService.initBluePrintCatalog()
93 * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
95 * @return List<BlueprintModelSearch> list of the controller blueprint archives
96 </BlueprintModelSearch> */
97 open fun allBlueprintModel(): List<BlueprintModelSearch> {
98 return blueprintModelSearchRepository.findAll()
102 * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
104 * @return List<BlueprintModelSearch> list of the controller blueprint archives
105 </BlueprintModelSearch> */
106 open fun allBlueprintModel(pageRequest: Pageable): Page<BlueprintModelSearch> {
107 return blueprintModelSearchRepository.findAll(pageRequest)
111 * This is a saveBlueprintModel method
113 * @param filePart filePart
114 * @return Mono<BlueprintModelSearch>
115 * @throws BluePrintException BluePrintException
116 </BlueprintModelSearch> */
117 @Throws(BluePrintException::class)
118 open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch {
120 return upload(filePart, false)
121 } catch (e: IOException) {
122 throw BluePrintException(
123 ErrorCode.IO_FILE_INTERRUPT.value,
124 "Error in Save CBA: ${e.message}", e
130 * This is a searchBlueprintModels method
133 * @return List<BlueprintModelSearch>
134 </BlueprintModelSearch> */
135 open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
136 return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
140 * This is a getBlueprintModelSearchByNameAndVersion method
143 * @param version version
144 * @return BlueprintModelSearch
145 * @throws BluePrintException BluePrintException
147 @Throws(BluePrintException::class)
148 open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch {
149 return blueprintModelSearchRepository.findByArtifactNameAndArtifactVersion(name, version)
150 ?: throw BluePrintException(
151 ErrorCode.RESOURCE_NOT_FOUND.value,
152 String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
157 * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
160 * @param version version
161 * @return ResponseEntity<Resource>
162 * @throws BluePrintException BluePrintException
164 @Throws(BluePrintException::class)
165 open fun downloadBlueprintModelFileByNameAndVersion(
168 ): ResponseEntity<Resource> {
170 val archiveByteArray = download(name, version)
171 val fileName = "${name}_$version.zip"
172 return prepareResourceEntity(fileName, archiveByteArray)
173 } catch (e: BluePrintException) {
174 throw BluePrintException(
175 ErrorCode.RESOURCE_NOT_FOUND.value,
176 String.format("Error while " + "downloading the CBA file: %s", e.message), e
182 * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
184 * @return ResponseEntity<Resource>
185 * @throws BluePrintException BluePrintException
187 @Throws(BluePrintException::class)
188 open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
189 val blueprintModel: BlueprintModel
191 blueprintModel = getBlueprintModel(id)
192 } catch (e: BluePrintException) {
193 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
196 val fileName = "${blueprintModel.artifactName}_${blueprintModel.artifactVersion}.zip"
197 val file = blueprintModel.blueprintModelContent?.content
198 ?: throw BluePrintException(
199 ErrorCode.RESOURCE_NOT_FOUND.value,
200 String.format("Error while downloading the CBA file: couldn't get model content")
202 return prepareResourceEntity(fileName, file)
206 * @return ResponseEntity<Resource>
208 private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
209 return ResponseEntity.ok()
210 .contentType(MediaType.parseMediaType("text/plain"))
211 .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
212 .body(ByteArrayResource(file))
216 * This is a getBlueprintModel method
219 * @return BlueprintModel
220 * @throws BluePrintException BluePrintException
222 @Throws(BluePrintException::class)
223 open fun getBlueprintModel(id: String): BlueprintModel {
224 val blueprintModel: BlueprintModel
225 val dbBlueprintModel = blueprintModelRepository.findById(id)
226 if (dbBlueprintModel.isPresent) {
227 blueprintModel = dbBlueprintModel.get()
229 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
230 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
232 return blueprintModel
236 * This is a getBlueprintModelByNameAndVersion method
239 * @param version version
240 * @return BlueprintModel
241 * @throws BluePrintException BluePrintException
243 @Throws(BluePrintException::class)
244 open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
245 val blueprintModel = blueprintModelRepository
246 .findByArtifactNameAndArtifactVersion(name, version)
247 if (blueprintModel != null) {
248 return blueprintModel
250 val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
251 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
256 * This is a getBlueprintModelSearch method
259 * @return BlueprintModelSearch
260 * @throws BluePrintException BluePrintException
262 @Throws(BluePrintException::class)
263 open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
264 return blueprintModelSearchRepository.findById(id)
265 ?: throw BluePrintException(
266 ErrorCode.RESOURCE_NOT_FOUND.value,
267 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
272 * This is a searchBluePrintModelsByKeyWord method to retrieve specific BlueprintModel in Database
273 * where keyword equals updatedBy or tags or artifcat name or artifcat version or artifact type
274 * @author Shaaban Ebrahim
277 * @return List<BlueprintModelSearch> list of the controller blueprint
278 </BlueprintModelSearch> */
279 open fun searchBluePrintModelsByKeyWord(keyWord: String): List<BlueprintModelSearch> {
280 return blueprintModelSearchRepository.findByUpdatedByOrTagsOrOrArtifactNameOrOrArtifactVersionOrArtifactType(
281 keyWord, keyWord, keyWord, keyWord, keyWord
286 * This is a searchBluePrintModelsByKeyWordPagebale method to retrieve specific BlueprintModel in Database
287 * where keyword equals updatedBy or tags or artifcat name or artifcat version or artifact type and pageable
288 * @author Shaaban Ebrahim
291 * @return List<BlueprintModelSearch> list of the controller blueprint
292 </BlueprintModelSearch> */
293 open fun searchBluePrintModelsByKeyWordPaged(keyWord: String, pageRequest: PageRequest): Page<BlueprintModelSearch> {
294 return blueprintModelSearchRepository.findByUpdatedByOrTagsOrOrArtifactNameOrOrArtifactVersionOrArtifactType(
305 * This is a deleteBlueprintModel method
308 * @throws BluePrintException BluePrintException
311 @Throws(BluePrintException::class)
312 open fun deleteBlueprintModel(id: String) {
313 val dbBlueprintModel = blueprintModelRepository.findById(id)
314 if (dbBlueprintModel != null && dbBlueprintModel.isPresent) {
315 blueprintModelContentRepository.deleteByBlueprintModel(dbBlueprintModel.get())
316 blueprintModelRepository.delete(dbBlueprintModel.get())
318 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
319 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
323 open suspend fun deleteBlueprintModel(name: String, version: String) {
324 blueprintsProcessorCatalogService.deleteFromDatabase(name, version)
328 * This is a CBA enrichBlueprint method
329 * Save the Zip File in archive location and extract the cba content.
330 * Populate the Enhancement Location
331 * Enhance the CBA content
332 * Compress the Enhanced Content
333 * Return back the the compressed content back to the caller.
335 * @param filePart filePart
336 * @return ResponseEntity<Resource>
337 * @throws BluePrintException BluePrintException
339 @Throws(BluePrintException::class)
340 open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
342 val enhancedByteArray = enrichBlueprintFileSource(filePart)
343 return BluePrintEnhancerUtils.prepareResourceEntity("enhanced-cba.zip", enhancedByteArray)
344 } catch (e: IOException) {
345 throw BluePrintException(
346 ErrorCode.IO_FILE_INTERRUPT.value,
347 "Error in Enriching CBA: ${e.message}", e
353 * This is a publishBlueprintModel method to change the status published to YES
355 * @param filePart filePart
356 * @return BlueprintModelSearch
357 * @throws BluePrintException BluePrintException
359 @Throws(BluePrintException::class)
360 open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
362 return upload(filePart, true)
363 } catch (e: Exception) {
364 throw BluePrintException(
365 ErrorCode.IO_FILE_INTERRUPT.value,
366 "Error in Publishing CBA: ${e.message}", e
371 /** Common CBA Save and Publish function for RestController and GRPC Handler, the [fileSource] may be
372 * byteArray or File Part type.*/
373 open suspend fun upload(fileSource: Any, validate: Boolean): BlueprintModelSearch {
374 val saveId = UUID.randomUUID().toString()
375 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
376 val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId)
378 val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
380 is FilePart -> BluePrintEnhancerUtils.filePartAsFile(fileSource, compressedFile)
381 is ByteArray -> BluePrintEnhancerUtils.byteArrayAsFile(fileSource, compressedFile)
383 // Save the Copied file to Database
384 val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate)
386 return blueprintModelSearchRepository.findById(blueprintId)
387 ?: throw BluePrintException(
388 ErrorCode.RESOURCE_NOT_FOUND.value,
389 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId)
391 } catch (e: IOException) {
392 throw BluePrintException(
393 ErrorCode.IO_FILE_INTERRUPT.value,
394 "Error in Upload CBA: ${e.message}", e
397 // Clean blueprint script cache
398 val cacheKey = BluePrintFileUtils
399 .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId))
400 BluePrintCompileCache.cleanClassLoader(cacheKey)
401 deleteNBDir(blueprintArchive)
402 deleteNBDir(blueprintWorking)
406 /** Common CBA download function for RestController and GRPC Handler, the [fileSource] may be
407 * byteArray or File Part type.*/
408 open fun download(name: String, version: String): ByteArray {
410 val blueprintModel = getBlueprintModelByNameAndVersion(name, version)
411 return blueprintModel.blueprintModelContent?.content
412 ?: throw BluePrintException(
413 ErrorCode.RESOURCE_NOT_FOUND.value,
414 String.format("Error while downloading the CBA file: couldn't get model content")
416 } catch (e: BluePrintException) {
417 throw BluePrintException(
418 ErrorCode.RESOURCE_NOT_FOUND.value,
419 String.format("Error while " + "downloading the CBA file: %s", e.message), e
424 /** Common CBA Enrich function for RestController and GRPC Handler, the [fileSource] may be
425 * byteArray or File Part type.*/
426 open suspend fun enrichBlueprintFileSource(fileSource: Any): ByteArray {
427 val enhanceId = UUID.randomUUID().toString()
428 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
429 val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
432 is FilePart -> BluePrintEnhancerUtils
433 .copyFilePartToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
434 is ByteArray -> BluePrintEnhancerUtils
435 .copyByteArrayToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
436 } // Enhance the Blue Prints
437 bluePrintEnhancerService.enhance(blueprintWorkingDir)
439 return BluePrintEnhancerUtils.compressEnhanceDirAndReturnByteArray(blueprintWorkingDir, blueprintArchive)
440 } catch (e: IOException) {
441 throw BluePrintException(
442 ErrorCode.IO_FILE_INTERRUPT.value,
443 "Error in Enriching CBA: ${e.message}", e
446 BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
452 private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
453 private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"