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 kotlinx.coroutines.reactive.awaitSingle
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.utils.BluePrintEnhancerUtils
28 import org.onap.ccsdk.cds.controllerblueprints.core.*
29 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
30 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
31 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
32 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintEnhancerService
33 import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintCompileCache
34 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
35 import org.slf4j.LoggerFactory
36 import org.springframework.core.io.ByteArrayResource
37 import org.springframework.core.io.Resource
38 import org.springframework.http.HttpHeaders
39 import org.springframework.http.MediaType
40 import org.springframework.http.ResponseEntity
41 import org.springframework.http.codec.multipart.FilePart
42 import org.springframework.stereotype.Service
43 import org.springframework.transaction.annotation.Transactional
45 import java.io.IOException
49 * BlueprintModelHandler Purpose: Handler service to handle the request from BlurPrintModelRest
51 * @author Brinda Santh
56 open class BluePrintModelHandler(private val blueprintsProcessorCatalogService: BluePrintCatalogService,
57 private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
58 private val blueprintModelSearchRepository: BlueprintModelSearchRepository,
59 private val blueprintModelRepository: BlueprintModelRepository,
60 private val blueprintModelContentRepository: BlueprintModelContentRepository,
61 private val bluePrintEnhancerService: BluePrintEnhancerService) {
63 private val log = LoggerFactory.getLogger(BluePrintModelHandler::class.java)!!
66 * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
68 * @return List<BlueprintModelSearch> list of the controller blueprint archives
69 </BlueprintModelSearch> */
70 open fun allBlueprintModel(): List<BlueprintModelSearch> {
71 return blueprintModelSearchRepository.findAll()
75 * This is a saveBlueprintModel method
77 * @param filePart filePart
78 * @return Mono<BlueprintModelSearch>
79 * @throws BluePrintException BluePrintException
80 </BlueprintModelSearch> */
81 @Throws(BluePrintException::class)
82 open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch {
84 val blueprintId = upload(filePart, false)
85 // Check and Return the Saved File
86 val blueprintModelSearch = blueprintModelSearchRepository.findById(blueprintId)
87 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
88 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
90 log.info("Save successful for blueprint(${blueprintModelSearch.artifactName}) " +
91 "version(${blueprintModelSearch.artifactVersion})")
92 return blueprintModelSearch
93 } catch (e: IOException) {
94 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
95 "Error in Save CBA: ${e.message}", e)
101 * This is a searchBlueprintModels method
104 * @return List<BlueprintModelSearch>
105 </BlueprintModelSearch> */
106 open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
107 return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
111 * This is a getBlueprintModelSearchByNameAndVersion method
114 * @param version version
115 * @return BlueprintModelSearch
116 * @throws BluePrintException BluePrintException
118 @Throws(BluePrintException::class)
119 open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch {
120 return blueprintModelSearchRepository.findByArtifactNameAndArtifactVersion(name, version)
121 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
122 String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version))
127 * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
130 * @param version version
131 * @return ResponseEntity<Resource>
132 * @throws BluePrintException BluePrintException
134 @Throws(BluePrintException::class)
135 open fun downloadBlueprintModelFileByNameAndVersion(name: String,
136 version: String): ResponseEntity<Resource> {
137 val blueprintModel: BlueprintModel
139 blueprintModel = getBlueprintModelByNameAndVersion(name, version)
140 } catch (e: BluePrintException) {
141 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
142 String.format("Error while " + "downloading the CBA file: %s", e.message), e)
145 val fileName = blueprintModel.id + ".zip"
146 val file = blueprintModel.blueprintModelContent?.content
147 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
148 String.format("Error while downloading the CBA file: couldn't get model content"))
149 return prepareResourceEntity(fileName, file)
153 * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
155 * @return ResponseEntity<Resource>
156 * @throws BluePrintException BluePrintException
158 @Throws(BluePrintException::class)
159 open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
160 val blueprintModel: BlueprintModel
162 blueprintModel = getBlueprintModel(id)
163 } catch (e: BluePrintException) {
164 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
167 val fileName = blueprintModel.id + ".zip"
168 val file = blueprintModel.blueprintModelContent?.content
169 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
170 String.format("Error while downloading the CBA file: couldn't get model content"))
171 return prepareResourceEntity(fileName, file)
175 * @return ResponseEntity<Resource>
177 private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
178 return ResponseEntity.ok()
179 .contentType(MediaType.parseMediaType("text/plain"))
180 .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
181 .body(ByteArrayResource(file))
185 * This is a getBlueprintModel method
188 * @return BlueprintModel
189 * @throws BluePrintException BluePrintException
191 @Throws(BluePrintException::class)
192 open fun getBlueprintModel(id: String): BlueprintModel {
193 val blueprintModel: BlueprintModel
194 val dbBlueprintModel = blueprintModelRepository.findById(id)
195 if (dbBlueprintModel.isPresent) {
196 blueprintModel = dbBlueprintModel.get()
198 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
199 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
201 return blueprintModel
205 * This is a getBlueprintModelByNameAndVersion method
208 * @param version version
209 * @return BlueprintModel
210 * @throws BluePrintException BluePrintException
212 @Throws(BluePrintException::class)
213 open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
214 val blueprintModel = blueprintModelRepository
215 .findByArtifactNameAndArtifactVersion(name, version)
216 if (blueprintModel != null) {
217 return blueprintModel
219 val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
220 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
225 * This is a getBlueprintModelSearch method
228 * @return BlueprintModelSearch
229 * @throws BluePrintException BluePrintException
231 @Throws(BluePrintException::class)
232 open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
233 return blueprintModelSearchRepository.findById(id)
234 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
235 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id))
239 * This is a deleteBlueprintModel method
242 * @throws BluePrintException BluePrintException
245 @Throws(BluePrintException::class)
246 open fun deleteBlueprintModel(id: String) {
247 val dbBlueprintModel = blueprintModelRepository.findById(id)
248 if (dbBlueprintModel != null && dbBlueprintModel.isPresent) {
249 blueprintModelContentRepository.deleteByBlueprintModel(dbBlueprintModel.get())
250 blueprintModelRepository.delete(dbBlueprintModel.get())
252 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
253 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
257 open suspend fun deleteBlueprintModel(name: String, version: String) {
258 blueprintsProcessorCatalogService.deleteFromDatabase(name, version)
262 * This is a CBA enrichBlueprint method
263 * Save the Zip File in archive location and extract the cba content.
264 * Populate the Enhancement Location
265 * Enhance the CBA content
266 * Compress the Enhanced Content
267 * Return back the the compressed content back to the caller.
269 * @param filePart filePart
270 * @return ResponseEntity<Resource>
271 * @throws BluePrintException BluePrintException
273 @Throws(BluePrintException::class)
274 open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
275 val enhanceId = UUID.randomUUID().toString()
276 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
277 val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
279 BluePrintEnhancerUtils.decompressFilePart(filePart, blueprintArchive, blueprintWorkingDir)
281 // Enhance the Blue Prints
282 bluePrintEnhancerService.enhance(blueprintWorkingDir)
284 return BluePrintEnhancerUtils.compressToFilePart(blueprintWorkingDir, blueprintArchive)
286 } catch (e: IOException) {
287 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
288 "Error in Enriching CBA: ${e.message}", e)
290 BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
295 * This is a publishBlueprintModel method to change the status published to YES
297 * @param filePart filePart
298 * @return BlueprintModelSearch
299 * @throws BluePrintException BluePrintException
301 @Throws(BluePrintException::class)
302 open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
304 val blueprintId = upload(filePart, true)
306 return blueprintModelSearchRepository.findById(blueprintId)
307 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
308 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
310 } catch (e: Exception) {
311 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
312 "Error in Publishing CBA: ${e.message}", e)
316 //TODO("Combine Rest and GRPC Handler")
317 suspend fun upload(filePart: FilePart, validate: Boolean): String {
318 val saveId = UUID.randomUUID().toString()
319 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
320 val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId)
322 val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
323 compressedFile.parentFile.reCreateNBDirs()
324 // Copy the File Part to Local File
325 copyFromFilePart(filePart, compressedFile)
326 // Save the Copied file to Database
327 return blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate)
328 } catch (e: IOException) {
329 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
330 "Error in Upload CBA: ${e.message}", e)
332 // Clean blueprint script cache
333 val cacheKey = BluePrintFileUtils
334 .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId))
335 BluePrintCompileCache.cleanClassLoader(cacheKey)
336 deleteNBDir(blueprintArchive)
337 deleteNBDir(blueprintWorking)
341 private suspend fun copyFromFilePart(filePart: FilePart, targetFile: File): File {
342 return filePart.transferTo(targetFile)
343 .thenReturn(targetFile)
349 private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
350 private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"