2 * Copyright © 2017-2018 AT&T Intellectual Property.
3 * Modifications Copyright © 2019 Bell Canada.
4 * Modifications Copyright © 2019 IBM.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler
21 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModel
22 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModelSearch
23 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.repository.BlueprintModelContentRepository
24 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.repository.BlueprintModelRepository
25 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.repository.BlueprintModelSearchRepository
26 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.utils.BluePrintEnhancerUtils
27 import org.onap.ccsdk.cds.controllerblueprints.core.*
28 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
29 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
30 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
31 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintEnhancerService
32 import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintCompileCache
33 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
34 import org.springframework.core.io.ByteArrayResource
35 import org.springframework.core.io.Resource
36 import org.springframework.http.HttpHeaders
37 import org.springframework.http.MediaType
38 import org.springframework.http.ResponseEntity
39 import org.springframework.http.codec.multipart.FilePart
40 import org.springframework.stereotype.Service
41 import org.springframework.transaction.annotation.Transactional
42 import java.io.IOException
46 * BlueprintModelHandler Purpose: Handler service to handle the request from BlurPrintModelRest
48 * @author Brinda Santh
53 open class BluePrintModelHandler(private val blueprintsProcessorCatalogService: BluePrintCatalogService,
54 private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
55 private val blueprintModelSearchRepository: BlueprintModelSearchRepository,
56 private val blueprintModelRepository: BlueprintModelRepository,
57 private val blueprintModelContentRepository: BlueprintModelContentRepository,
58 private val bluePrintEnhancerService: BluePrintEnhancerService) {
60 private val log = logger(BluePrintModelHandler::class)
63 * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
65 * @return List<BlueprintModelSearch> list of the controller blueprint archives
66 </BlueprintModelSearch> */
67 open fun allBlueprintModel(): List<BlueprintModelSearch> {
68 return blueprintModelSearchRepository.findAll()
72 * This is a saveBlueprintModel method
74 * @param filePart filePart
75 * @return Mono<BlueprintModelSearch>
76 * @throws BluePrintException BluePrintException
77 </BlueprintModelSearch> */
78 @Throws(BluePrintException::class)
79 open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch {
81 return upload(filePart, false)
82 } catch (e: IOException) {
83 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
84 "Error in Save CBA: ${e.message}", e)
90 * This is a searchBlueprintModels method
93 * @return List<BlueprintModelSearch>
94 </BlueprintModelSearch> */
95 open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
96 return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
100 * This is a getBlueprintModelSearchByNameAndVersion method
103 * @param version version
104 * @return BlueprintModelSearch
105 * @throws BluePrintException BluePrintException
107 @Throws(BluePrintException::class)
108 open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch {
109 return blueprintModelSearchRepository.findByArtifactNameAndArtifactVersion(name, version)
110 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
111 String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version))
116 * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
119 * @param version version
120 * @return ResponseEntity<Resource>
121 * @throws BluePrintException BluePrintException
123 @Throws(BluePrintException::class)
124 open fun downloadBlueprintModelFileByNameAndVersion(name: String,
125 version: String): ResponseEntity<Resource> {
127 val archiveByteArray = download(name, version)
128 val fileName = "${name}_$version.zip"
129 return prepareResourceEntity(fileName, archiveByteArray)
130 } catch (e: BluePrintException) {
131 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
132 String.format("Error while " + "downloading the CBA file: %s", e.message), e)
137 * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
139 * @return ResponseEntity<Resource>
140 * @throws BluePrintException BluePrintException
142 @Throws(BluePrintException::class)
143 open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
144 val blueprintModel: BlueprintModel
146 blueprintModel = getBlueprintModel(id)
147 } catch (e: BluePrintException) {
148 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
151 val fileName = "${blueprintModel.artifactName}_${blueprintModel.artifactVersion}.zip"
152 val file = blueprintModel.blueprintModelContent?.content
153 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
154 String.format("Error while downloading the CBA file: couldn't get model content"))
155 return prepareResourceEntity(fileName, file)
159 * @return ResponseEntity<Resource>
161 private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
162 return ResponseEntity.ok()
163 .contentType(MediaType.parseMediaType("text/plain"))
164 .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
165 .body(ByteArrayResource(file))
169 * This is a getBlueprintModel method
172 * @return BlueprintModel
173 * @throws BluePrintException BluePrintException
175 @Throws(BluePrintException::class)
176 open fun getBlueprintModel(id: String): BlueprintModel {
177 val blueprintModel: BlueprintModel
178 val dbBlueprintModel = blueprintModelRepository.findById(id)
179 if (dbBlueprintModel.isPresent) {
180 blueprintModel = dbBlueprintModel.get()
182 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
183 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
185 return blueprintModel
189 * This is a getBlueprintModelByNameAndVersion method
192 * @param version version
193 * @return BlueprintModel
194 * @throws BluePrintException BluePrintException
196 @Throws(BluePrintException::class)
197 open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
198 val blueprintModel = blueprintModelRepository
199 .findByArtifactNameAndArtifactVersion(name, version)
200 if (blueprintModel != null) {
201 return blueprintModel
203 val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
204 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
209 * This is a getBlueprintModelSearch method
212 * @return BlueprintModelSearch
213 * @throws BluePrintException BluePrintException
215 @Throws(BluePrintException::class)
216 open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
217 return blueprintModelSearchRepository.findById(id)
218 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
219 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id))
223 * This is a deleteBlueprintModel method
226 * @throws BluePrintException BluePrintException
229 @Throws(BluePrintException::class)
230 open fun deleteBlueprintModel(id: String) {
231 val dbBlueprintModel = blueprintModelRepository.findById(id)
232 if (dbBlueprintModel != null && dbBlueprintModel.isPresent) {
233 blueprintModelContentRepository.deleteByBlueprintModel(dbBlueprintModel.get())
234 blueprintModelRepository.delete(dbBlueprintModel.get())
236 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
237 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
241 open suspend fun deleteBlueprintModel(name: String, version: String) {
242 blueprintsProcessorCatalogService.deleteFromDatabase(name, version)
246 * This is a CBA enrichBlueprint method
247 * Save the Zip File in archive location and extract the cba content.
248 * Populate the Enhancement Location
249 * Enhance the CBA content
250 * Compress the Enhanced Content
251 * Return back the the compressed content back to the caller.
253 * @param filePart filePart
254 * @return ResponseEntity<Resource>
255 * @throws BluePrintException BluePrintException
257 @Throws(BluePrintException::class)
258 open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
260 val enhancedByteArray = enrichBlueprintFileSource(filePart)
261 return BluePrintEnhancerUtils.prepareResourceEntity("enhanced-cba.zip", enhancedByteArray)
262 } catch (e: IOException) {
263 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
264 "Error in Enriching CBA: ${e.message}", e)
269 * This is a publishBlueprintModel method to change the status published to YES
271 * @param filePart filePart
272 * @return BlueprintModelSearch
273 * @throws BluePrintException BluePrintException
275 @Throws(BluePrintException::class)
276 open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
278 return upload(filePart, true)
279 } catch (e: Exception) {
280 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
281 "Error in Publishing CBA: ${e.message}", e)
285 /** Common CBA Save and Publish function for RestController and GRPC Handler, the [fileSource] may be
286 * byteArray or File Part type.*/
287 open suspend fun upload(fileSource: Any, validate: Boolean): BlueprintModelSearch {
288 val saveId = UUID.randomUUID().toString()
289 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
290 val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId)
292 val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
294 is FilePart -> BluePrintEnhancerUtils.filePartAsFile(fileSource, compressedFile)
295 is ByteArray -> BluePrintEnhancerUtils.byteArrayAsFile(fileSource, compressedFile)
297 // Save the Copied file to Database
298 val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate)
300 return blueprintModelSearchRepository.findById(blueprintId)
301 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
302 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
304 } catch (e: IOException) {
305 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
306 "Error in Upload CBA: ${e.message}", e)
308 // Clean blueprint script cache
309 val cacheKey = BluePrintFileUtils
310 .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId))
311 BluePrintCompileCache.cleanClassLoader(cacheKey)
312 deleteNBDir(blueprintArchive)
313 deleteNBDir(blueprintWorking)
317 /** Common CBA download function for RestController and GRPC Handler, the [fileSource] may be
318 * byteArray or File Part type.*/
319 open fun download(name: String, version: String): ByteArray {
321 val blueprintModel = getBlueprintModelByNameAndVersion(name, version)
322 return blueprintModel.blueprintModelContent?.content
323 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
324 String.format("Error while downloading the CBA file: couldn't get model content"))
325 } catch (e: BluePrintException) {
326 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
327 String.format("Error while " + "downloading the CBA file: %s", e.message), e)
331 /** Common CBA Enrich function for RestController and GRPC Handler, the [fileSource] may be
332 * byteArray or File Part type.*/
333 open suspend fun enrichBlueprintFileSource(fileSource: Any): ByteArray {
334 val enhanceId = UUID.randomUUID().toString()
335 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
336 val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
339 is FilePart -> BluePrintEnhancerUtils
340 .copyFilePartToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
341 is ByteArray -> BluePrintEnhancerUtils
342 .copyByteArrayToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
343 } // Enhance the Blue Prints
344 bluePrintEnhancerService.enhance(blueprintWorkingDir)
346 return BluePrintEnhancerUtils.compressEnhanceDirAndReturnByteArray(blueprintWorkingDir, blueprintArchive)
348 } catch (e: IOException) {
349 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
350 "Error in Enriching CBA: ${e.message}", e)
352 BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
358 private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
359 private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"