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.data.domain.Page
37 import org.springframework.http.HttpHeaders
38 import org.springframework.http.MediaType
39 import org.springframework.http.ResponseEntity
40 import org.springframework.http.codec.multipart.FilePart
41 import org.springframework.stereotype.Service
42 import org.springframework.transaction.annotation.Transactional
43 import java.io.IOException
45 import org.springframework.data.domain.Pageable
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 = logger(BluePrintModelHandler::class)
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 getAllBlueprintModel method to retrieve all the BlueprintModel in Database
77 * @return List<BlueprintModelSearch> list of the controller blueprint archives
78 </BlueprintModelSearch> */
79 open fun allBlueprintModel(pageRequest: Pageable): Page<BlueprintModelSearch> {
80 return blueprintModelSearchRepository.findAll(pageRequest)
84 * This is a saveBlueprintModel method
86 * @param filePart filePart
87 * @return Mono<BlueprintModelSearch>
88 * @throws BluePrintException BluePrintException
89 </BlueprintModelSearch> */
90 @Throws(BluePrintException::class)
91 open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch {
93 return upload(filePart, false)
94 } catch (e: IOException) {
95 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
96 "Error in Save CBA: ${e.message}", e)
102 * This is a searchBlueprintModels method
105 * @return List<BlueprintModelSearch>
106 </BlueprintModelSearch> */
107 open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
108 return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
112 * This is a getBlueprintModelSearchByNameAndVersion method
115 * @param version version
116 * @return BlueprintModelSearch
117 * @throws BluePrintException BluePrintException
119 @Throws(BluePrintException::class)
120 open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch {
121 return blueprintModelSearchRepository.findByArtifactNameAndArtifactVersion(name, version)
122 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
123 String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version))
128 * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
131 * @param version version
132 * @return ResponseEntity<Resource>
133 * @throws BluePrintException BluePrintException
135 @Throws(BluePrintException::class)
136 open fun downloadBlueprintModelFileByNameAndVersion(name: String,
137 version: String): ResponseEntity<Resource> {
139 val archiveByteArray = download(name, version)
140 val fileName = "${name}_$version.zip"
141 return prepareResourceEntity(fileName, archiveByteArray)
142 } catch (e: BluePrintException) {
143 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
144 String.format("Error while " + "downloading the CBA file: %s", e.message), e)
149 * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
151 * @return ResponseEntity<Resource>
152 * @throws BluePrintException BluePrintException
154 @Throws(BluePrintException::class)
155 open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
156 val blueprintModel: BlueprintModel
158 blueprintModel = getBlueprintModel(id)
159 } catch (e: BluePrintException) {
160 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
163 val fileName = "${blueprintModel.artifactName}_${blueprintModel.artifactVersion}.zip"
164 val file = blueprintModel.blueprintModelContent?.content
165 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
166 String.format("Error while downloading the CBA file: couldn't get model content"))
167 return prepareResourceEntity(fileName, file)
171 * @return ResponseEntity<Resource>
173 private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
174 return ResponseEntity.ok()
175 .contentType(MediaType.parseMediaType("text/plain"))
176 .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
177 .body(ByteArrayResource(file))
181 * This is a getBlueprintModel method
184 * @return BlueprintModel
185 * @throws BluePrintException BluePrintException
187 @Throws(BluePrintException::class)
188 open fun getBlueprintModel(id: String): BlueprintModel {
189 val blueprintModel: BlueprintModel
190 val dbBlueprintModel = blueprintModelRepository.findById(id)
191 if (dbBlueprintModel.isPresent) {
192 blueprintModel = dbBlueprintModel.get()
194 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
195 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
197 return blueprintModel
201 * This is a getBlueprintModelByNameAndVersion method
204 * @param version version
205 * @return BlueprintModel
206 * @throws BluePrintException BluePrintException
208 @Throws(BluePrintException::class)
209 open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
210 val blueprintModel = blueprintModelRepository
211 .findByArtifactNameAndArtifactVersion(name, version)
212 if (blueprintModel != null) {
213 return blueprintModel
215 val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
216 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
221 * This is a getBlueprintModelSearch method
224 * @return BlueprintModelSearch
225 * @throws BluePrintException BluePrintException
227 @Throws(BluePrintException::class)
228 open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
229 return blueprintModelSearchRepository.findById(id)
230 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
231 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id))
235 * This is a deleteBlueprintModel method
238 * @throws BluePrintException BluePrintException
241 @Throws(BluePrintException::class)
242 open fun deleteBlueprintModel(id: String) {
243 val dbBlueprintModel = blueprintModelRepository.findById(id)
244 if (dbBlueprintModel != null && dbBlueprintModel.isPresent) {
245 blueprintModelContentRepository.deleteByBlueprintModel(dbBlueprintModel.get())
246 blueprintModelRepository.delete(dbBlueprintModel.get())
248 val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
249 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
253 open suspend fun deleteBlueprintModel(name: String, version: String) {
254 blueprintsProcessorCatalogService.deleteFromDatabase(name, version)
258 * This is a CBA enrichBlueprint method
259 * Save the Zip File in archive location and extract the cba content.
260 * Populate the Enhancement Location
261 * Enhance the CBA content
262 * Compress the Enhanced Content
263 * Return back the the compressed content back to the caller.
265 * @param filePart filePart
266 * @return ResponseEntity<Resource>
267 * @throws BluePrintException BluePrintException
269 @Throws(BluePrintException::class)
270 open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
272 val enhancedByteArray = enrichBlueprintFileSource(filePart)
273 return BluePrintEnhancerUtils.prepareResourceEntity("enhanced-cba.zip", enhancedByteArray)
274 } catch (e: IOException) {
275 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
276 "Error in Enriching CBA: ${e.message}", e)
281 * This is a publishBlueprintModel method to change the status published to YES
283 * @param filePart filePart
284 * @return BlueprintModelSearch
285 * @throws BluePrintException BluePrintException
287 @Throws(BluePrintException::class)
288 open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
290 return upload(filePart, true)
291 } catch (e: Exception) {
292 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
293 "Error in Publishing CBA: ${e.message}", e)
297 /** Common CBA Save and Publish function for RestController and GRPC Handler, the [fileSource] may be
298 * byteArray or File Part type.*/
299 open suspend fun upload(fileSource: Any, validate: Boolean): BlueprintModelSearch {
300 val saveId = UUID.randomUUID().toString()
301 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
302 val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId)
304 val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
306 is FilePart -> BluePrintEnhancerUtils.filePartAsFile(fileSource, compressedFile)
307 is ByteArray -> BluePrintEnhancerUtils.byteArrayAsFile(fileSource, compressedFile)
309 // Save the Copied file to Database
310 val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate)
312 return blueprintModelSearchRepository.findById(blueprintId)
313 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
314 String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
316 } catch (e: IOException) {
317 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
318 "Error in Upload CBA: ${e.message}", e)
320 // Clean blueprint script cache
321 val cacheKey = BluePrintFileUtils
322 .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId))
323 BluePrintCompileCache.cleanClassLoader(cacheKey)
324 deleteNBDir(blueprintArchive)
325 deleteNBDir(blueprintWorking)
329 /** Common CBA download function for RestController and GRPC Handler, the [fileSource] may be
330 * byteArray or File Part type.*/
331 open fun download(name: String, version: String): ByteArray {
333 val blueprintModel = getBlueprintModelByNameAndVersion(name, version)
334 return blueprintModel.blueprintModelContent?.content
335 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
336 String.format("Error while downloading the CBA file: couldn't get model content"))
337 } catch (e: BluePrintException) {
338 throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
339 String.format("Error while " + "downloading the CBA file: %s", e.message), e)
343 /** Common CBA Enrich function for RestController and GRPC Handler, the [fileSource] may be
344 * byteArray or File Part type.*/
345 open suspend fun enrichBlueprintFileSource(fileSource: Any): ByteArray {
346 val enhanceId = UUID.randomUUID().toString()
347 val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
348 val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
351 is FilePart -> BluePrintEnhancerUtils
352 .copyFilePartToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
353 is ByteArray -> BluePrintEnhancerUtils
354 .copyByteArrayToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
355 } // Enhance the Blue Prints
356 bluePrintEnhancerService.enhance(blueprintWorkingDir)
358 return BluePrintEnhancerUtils.compressEnhanceDirAndReturnByteArray(blueprintWorkingDir, blueprintArchive)
360 } catch (e: IOException) {
361 throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
362 "Error in Enriching CBA: ${e.message}", e)
364 BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
370 private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
371 private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"