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.*
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.interfaces.BluePrintCatalogService
34 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintEnhancerService
35 import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintCompileCache
36 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
37 import org.springframework.core.io.ByteArrayResource
38 import org.springframework.core.io.Resource
39 import org.springframework.data.domain.Page
40 import org.springframework.data.domain.PageRequest
41 import org.springframework.data.domain.Pageable
42 import org.springframework.http.HttpHeaders
43 import org.springframework.http.MediaType
44 import org.springframework.http.ResponseEntity
45 import org.springframework.http.codec.multipart.FilePart
46 import org.springframework.stereotype.Service
47 import org.springframework.transaction.annotation.Transactional
48 import java.io.IOException
53 * BlueprintModelHandler Purpose: Handler service to handle the request from BlurPrintModelRest
55 * @author Brinda Santh
60 open class BluePrintModelHandler(private val bluePrintDatabaseLoadService: BluePrintDatabaseLoadService,
61 private val blueprintsProcessorCatalogService: BluePrintCatalogService,
62 private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
63 private val blueprintModelSearchRepository: BlueprintModelSearchRepository,
64 private val blueprintModelRepository: BlueprintModelRepository,
65 private val blueprintModelContentRepository: BlueprintModelContentRepository,
66 private val bluePrintEnhancerService: BluePrintEnhancerService) {
68 private val log = logger(BluePrintModelHandler::class)
71 open suspend fun bootstrapBlueprint(bootstrapRequest: BootstrapRequest) {
72 log.info("Bootstrap request with type load(${bootstrapRequest.loadModelType}), " +
73 "resource dictionary load(${bootstrapRequest.loadResourceDictionary}) and " +
74 "cba load(${bootstrapRequest.loadCBA})")
75 if (bootstrapRequest.loadModelType) {
76 bluePrintDatabaseLoadService.initModelTypes()
78 if (bootstrapRequest.loadResourceDictionary) {
79 bluePrintDatabaseLoadService.initResourceDictionary()
81 if (bootstrapRequest.loadCBA) {
82 bluePrintDatabaseLoadService.initBluePrintCatalog()
87 * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
89 * @return List<BlueprintModelSearch> list of the controller blueprint archives
90 </BlueprintModelSearch> */
91 open fun allBlueprintModel(): List<BlueprintModelSearch> {
92 return blueprintModelSearchRepository.findAll()
96 * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
98 * @return List<BlueprintModelSearch> list of the controller blueprint archives
99 </BlueprintModelSearch> */
100 open fun allBlueprintModel(pageRequest: Pageable): Page<BlueprintModelSearch> {
101 return blueprintModelSearchRepository.findAll(pageRequest)
105 * This is a saveBlueprintModel method
107 * @param filePart filePart
108 * @return Mono<BlueprintModelSearch>
109 * @throws BluePrintException BluePrintException
110 </BlueprintModelSearch> */
111 @Throws(BluePrintException::class)
112 open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch {
114 return upload(filePart, false)
115 } catch (e: IOException) {
116 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
117 "Error in Save CBA: ${e.message}", e)
123 * This is a searchBlueprintModels method
126 * @return List<BlueprintModelSearch>
127 </BlueprintModelSearch> */
128 open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
129 return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
133 * This is a getBlueprintModelSearchByNameAndVersion method
136 * @param version version
137 * @return BlueprintModelSearch
138 * @throws BluePrintException BluePrintException
140 @Throws(BluePrintException::class)
141 open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch {
142 return blueprintModelSearchRepository.findByArtifactNameAndArtifactVersion(name, version)
143 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
144 String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version))
149 * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
152 * @param version version
153 * @return ResponseEntity<Resource>
154 * @throws BluePrintException BluePrintException
156 @Throws(BluePrintException::class)
157 open fun downloadBlueprintModelFileByNameAndVersion(name: String,
158 version: String): ResponseEntity<Resource> {
160 val archiveByteArray = download(name, version)
161 val fileName = "${name}_$version.zip"
162 return prepareResourceEntity(fileName, archiveByteArray)
163 } catch (e: BluePrintException) {
164 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
165 String.format("Error while " + "downloading the CBA file: %s", e.message), e)
170 * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
172 * @return ResponseEntity<Resource>
173 * @throws BluePrintException BluePrintException
175 @Throws(BluePrintException::class)
176 open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
177 val blueprintModel: BlueprintModel
179 blueprintModel = getBlueprintModel(id)
180 } catch (e: BluePrintException) {
181 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
184 val fileName = "${blueprintModel.artifactName}_${blueprintModel.artifactVersion}.zip"
185 val file = blueprintModel.blueprintModelContent?.content
186 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
187 String.format("Error while downloading the CBA file: couldn't get model content"))
188 return prepareResourceEntity(fileName, file)
192 * @return ResponseEntity<Resource>
194 private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
195 return ResponseEntity.ok()
196 .contentType(MediaType.parseMediaType("text/plain"))
197 .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
198 .body(ByteArrayResource(file))
202 * This is a getBlueprintModel method
205 * @return BlueprintModel
206 * @throws BluePrintException BluePrintException
208 @Throws(BluePrintException::class)
209 open fun getBlueprintModel(id: String): BlueprintModel {
210 val blueprintModel: BlueprintModel
211 val dbBlueprintModel = blueprintModelRepository.findById(id)
212 if (dbBlueprintModel.isPresent) {
213 blueprintModel = dbBlueprintModel.get()
215 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
216 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
218 return blueprintModel
222 * This is a getBlueprintModelByNameAndVersion method
225 * @param version version
226 * @return BlueprintModel
227 * @throws BluePrintException BluePrintException
229 @Throws(BluePrintException::class)
230 open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
231 val blueprintModel = blueprintModelRepository
232 .findByArtifactNameAndArtifactVersion(name, version)
233 if (blueprintModel != null) {
234 return blueprintModel
236 val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
237 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
242 * This is a getBlueprintModelSearch method
245 * @return BlueprintModelSearch
246 * @throws BluePrintException BluePrintException
248 @Throws(BluePrintException::class)
249 open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
250 return blueprintModelSearchRepository.findById(id)
251 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
252 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id))
256 * This is a searchBluePrintModelsByKeyWord method to retrieve specific BlueprintModel in Database
257 * where keyword equals updatedBy or tags or artifcat name or artifcat version or artifact type
258 * @author Shaaban Ebrahim
261 * @return List<BlueprintModelSearch> list of the controller blueprint
262 </BlueprintModelSearch> */
263 open fun searchBluePrintModelsByKeyWord(keyWord: String): List<BlueprintModelSearch> {
264 return blueprintModelSearchRepository.findByUpdatedByOrTagsOrOrArtifactNameOrOrArtifactVersionOrArtifactType(
265 keyWord, keyWord, keyWord, keyWord, keyWord)
270 * This is a searchBluePrintModelsByKeyWordPagebale method to retrieve specific BlueprintModel in Database
271 * where keyword equals updatedBy or tags or artifcat name or artifcat version or artifact type and pageable
272 * @author Shaaban Ebrahim
275 * @return List<BlueprintModelSearch> list of the controller blueprint
276 </BlueprintModelSearch> */
277 open fun searchBluePrintModelsByKeyWordPaged(keyWord: String, pageRequest: PageRequest): Page<BlueprintModelSearch> {
278 return blueprintModelSearchRepository.findByUpdatedByOrTagsOrOrArtifactNameOrOrArtifactVersionOrArtifactType(keyWord, keyWord, keyWord, keyWord, keyWord, pageRequest)
282 * This is a deleteBlueprintModel method
285 * @throws BluePrintException BluePrintException
288 @Throws(BluePrintException::class)
289 open fun deleteBlueprintModel(id: String) {
290 val dbBlueprintModel = blueprintModelRepository.findById(id)
291 if (dbBlueprintModel != null && dbBlueprintModel.isPresent) {
292 blueprintModelContentRepository.deleteByBlueprintModel(dbBlueprintModel.get())
293 blueprintModelRepository.delete(dbBlueprintModel.get())
295 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
296 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
300 open suspend fun deleteBlueprintModel(name: String, version: String) {
301 blueprintsProcessorCatalogService.deleteFromDatabase(name, version)
305 * This is a CBA enrichBlueprint method
306 * Save the Zip File in archive location and extract the cba content.
307 * Populate the Enhancement Location
308 * Enhance the CBA content
309 * Compress the Enhanced Content
310 * Return back the the compressed content back to the caller.
312 * @param filePart filePart
313 * @return ResponseEntity<Resource>
314 * @throws BluePrintException BluePrintException
316 @Throws(BluePrintException::class)
317 open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
319 val enhancedByteArray = enrichBlueprintFileSource(filePart)
320 return BluePrintEnhancerUtils.prepareResourceEntity("enhanced-cba.zip", enhancedByteArray)
321 } catch (e: IOException) {
322 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
323 "Error in Enriching CBA: ${e.message}", e)
328 * This is a publishBlueprintModel method to change the status published to YES
330 * @param filePart filePart
331 * @return BlueprintModelSearch
332 * @throws BluePrintException BluePrintException
334 @Throws(BluePrintException::class)
335 open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
337 return upload(filePart, true)
338 } catch (e: Exception) {
339 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
340 "Error in Publishing CBA: ${e.message}", e)
344 /** Common CBA Save and Publish function for RestController and GRPC Handler, the [fileSource] may be
345 * byteArray or File Part type.*/
346 open suspend fun upload(fileSource: Any, validate: Boolean): BlueprintModelSearch {
347 val saveId = UUID.randomUUID().toString()
348 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
349 val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId)
351 val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
353 is FilePart -> BluePrintEnhancerUtils.filePartAsFile(fileSource, compressedFile)
354 is ByteArray -> BluePrintEnhancerUtils.byteArrayAsFile(fileSource, compressedFile)
356 // Save the Copied file to Database
357 val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate)
359 return blueprintModelSearchRepository.findById(blueprintId)
360 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
361 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
363 } catch (e: IOException) {
364 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
365 "Error in Upload CBA: ${e.message}", e)
367 // Clean blueprint script cache
368 val cacheKey = BluePrintFileUtils
369 .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId))
370 BluePrintCompileCache.cleanClassLoader(cacheKey)
371 deleteNBDir(blueprintArchive)
372 deleteNBDir(blueprintWorking)
376 /** Common CBA download function for RestController and GRPC Handler, the [fileSource] may be
377 * byteArray or File Part type.*/
378 open fun download(name: String, version: String): ByteArray {
380 val blueprintModel = getBlueprintModelByNameAndVersion(name, version)
381 return blueprintModel.blueprintModelContent?.content
382 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
383 String.format("Error while downloading the CBA file: couldn't get model content"))
384 } catch (e: BluePrintException) {
385 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
386 String.format("Error while " + "downloading the CBA file: %s", e.message), e)
390 /** Common CBA Enrich function for RestController and GRPC Handler, the [fileSource] may be
391 * byteArray or File Part type.*/
392 open suspend fun enrichBlueprintFileSource(fileSource: Any): ByteArray {
393 val enhanceId = UUID.randomUUID().toString()
394 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
395 val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
398 is FilePart -> BluePrintEnhancerUtils
399 .copyFilePartToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
400 is ByteArray -> BluePrintEnhancerUtils
401 .copyByteArrayToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
402 } // Enhance the Blue Prints
403 bluePrintEnhancerService.enhance(blueprintWorkingDir)
405 return BluePrintEnhancerUtils.compressEnhanceDirAndReturnByteArray(blueprintWorkingDir, blueprintArchive)
407 } catch (e: IOException) {
408 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
409 "Error in Enriching CBA: ${e.message}", e)
411 BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
417 private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
418 private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"