Merge "Updated golden README for config-assing"
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / inbounds / designer-api / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / designer / api / handler / BluePrintModelHandler.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2019 Bell Canada.
4  * Modifications Copyright © 2019 IBM.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 package org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler
20
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
43 import java.util.*
44
45 /**
46  * BlueprintModelHandler Purpose: Handler service to handle the request from BlurPrintModelRest
47  *
48  * @author Brinda Santh
49  * @version 1.0
50  */
51
52 @Service
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) {
59
60     private val log = logger(BluePrintModelHandler::class)
61
62     /**
63      * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
64      *
65      * @return List<BlueprintModelSearch> list of the controller blueprint archives
66     </BlueprintModelSearch> */
67     open fun allBlueprintModel(): List<BlueprintModelSearch> {
68         return blueprintModelSearchRepository.findAll()
69     }
70
71     /**
72      * This is a saveBlueprintModel method
73      *
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 {
80         try {
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)
85         }
86     }
87
88
89     /**
90      * This is a searchBlueprintModels method
91      *
92      * @param tags tags
93      * @return List<BlueprintModelSearch>
94     </BlueprintModelSearch> */
95     open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
96         return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
97     }
98
99     /**
100      * This is a getBlueprintModelSearchByNameAndVersion method
101      *
102      * @param name name
103      * @param version version
104      * @return BlueprintModelSearch
105      * @throws BluePrintException BluePrintException
106      */
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))
112
113     }
114
115     /**
116      * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
117      *
118      * @param name name
119      * @param version version
120      * @return ResponseEntity<Resource>
121      * @throws BluePrintException BluePrintException
122     </Resource> */
123     @Throws(BluePrintException::class)
124     open fun downloadBlueprintModelFileByNameAndVersion(name: String,
125                                                         version: String): ResponseEntity<Resource> {
126         try {
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)
133         }
134     }
135
136     /**
137      * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
138      *
139      * @return ResponseEntity<Resource>
140      * @throws BluePrintException BluePrintException
141     </Resource> */
142     @Throws(BluePrintException::class)
143     open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
144         val blueprintModel: BlueprintModel
145         try {
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)
149         }
150
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)
156     }
157
158     /**
159      * @return ResponseEntity<Resource>
160     </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))
166     }
167
168     /**
169      * This is a getBlueprintModel method
170      *
171      * @param id id
172      * @return BlueprintModel
173      * @throws BluePrintException BluePrintException
174      */
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()
181         } else {
182             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
183             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
184         }
185         return blueprintModel
186     }
187
188     /**
189      * This is a getBlueprintModelByNameAndVersion method
190      *
191      * @param name name
192      * @param version version
193      * @return BlueprintModel
194      * @throws BluePrintException BluePrintException
195      */
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
202         } else {
203             val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
204             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
205         }
206     }
207
208     /**
209      * This is a getBlueprintModelSearch method
210      *
211      * @param id id
212      * @return BlueprintModelSearch
213      * @throws BluePrintException BluePrintException
214      */
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))
220     }
221
222     /**
223      * This is a deleteBlueprintModel method
224      *
225      * @param id id
226      * @throws BluePrintException BluePrintException
227      */
228     @Transactional
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())
235         } else {
236             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
237             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
238         }
239     }
240
241     open suspend fun deleteBlueprintModel(name: String, version: String) {
242         blueprintsProcessorCatalogService.deleteFromDatabase(name, version)
243     }
244
245     /**
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.
252      *
253      * @param filePart filePart
254      * @return ResponseEntity<Resource>
255      * @throws BluePrintException BluePrintException
256      */
257     @Throws(BluePrintException::class)
258     open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
259         try {
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)
265         }
266     }
267
268     /**
269      * This is a publishBlueprintModel method to change the status published to YES
270      *
271      * @param filePart filePart
272      * @return BlueprintModelSearch
273      * @throws BluePrintException BluePrintException
274      */
275     @Throws(BluePrintException::class)
276     open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
277         try {
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)
282         }
283     }
284
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)
291         try {
292             val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
293             when (fileSource) {
294                 is FilePart -> BluePrintEnhancerUtils.filePartAsFile(fileSource, compressedFile)
295                 is ByteArray -> BluePrintEnhancerUtils.byteArrayAsFile(fileSource, compressedFile)
296             }
297             // Save the Copied file to Database
298             val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate)
299
300             return blueprintModelSearchRepository.findById(blueprintId)
301                     ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
302                             String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
303
304         } catch (e: IOException) {
305             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
306                     "Error in Upload CBA: ${e.message}", e)
307         } finally {
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)
314         }
315     }
316
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 {
320         try {
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)
328         }
329     }
330
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)
337         try {
338             when (fileSource) {
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)
345
346             return BluePrintEnhancerUtils.compressEnhanceDirAndReturnByteArray(blueprintWorkingDir, blueprintArchive)
347
348         } catch (e: IOException) {
349             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
350                     "Error in Enriching CBA: ${e.message}", e)
351         } finally {
352             BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
353         }
354     }
355
356     companion object {
357
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"
360     }
361 }