Merge "Fixed typo..."
[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  * Modifications Copyright © 2019 Orange.
6  *
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
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  */
19
20 package org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler
21
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.springframework.core.io.ByteArrayResource
36 import org.springframework.core.io.Resource
37 import org.springframework.data.domain.Page
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
44 import java.io.IOException
45 import java.util.*
46 import org.springframework.data.domain.Pageable
47
48
49 /**
50  * BlueprintModelHandler Purpose: Handler service to handle the request from BlurPrintModelRest
51  *
52  * @author Brinda Santh
53  * @version 1.0
54  */
55
56 @Service
57 open class BluePrintModelHandler(private val blueprintsProcessorCatalogService: BluePrintCatalogService,
58                                  private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
59                                  private val blueprintModelSearchRepository: BlueprintModelSearchRepository,
60                                  private val blueprintModelRepository: BlueprintModelRepository,
61                                  private val blueprintModelContentRepository: BlueprintModelContentRepository,
62                                  private val bluePrintEnhancerService: BluePrintEnhancerService) {
63
64     private val log = logger(BluePrintModelHandler::class)
65
66     /**
67      * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
68      *
69      * @return List<BlueprintModelSearch> list of the controller blueprint archives
70     </BlueprintModelSearch> */
71     open fun allBlueprintModel(): List<BlueprintModelSearch> {
72         return blueprintModelSearchRepository.findAll()
73     }
74
75     /**
76      * This is a getAllBlueprintModel method to retrieve all the BlueprintModel in Database
77      *
78      * @return List<BlueprintModelSearch> list of the controller blueprint archives
79     </BlueprintModelSearch> */
80     open fun allBlueprintModel(pageRequest: Pageable): Page<BlueprintModelSearch> {
81         return blueprintModelSearchRepository.findAll(pageRequest)
82     }
83
84     /**
85      * This is a saveBlueprintModel method
86      *
87      * @param filePart filePart
88      * @return Mono<BlueprintModelSearch>
89      * @throws BluePrintException BluePrintException
90     </BlueprintModelSearch> */
91     @Throws(BluePrintException::class)
92     open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch {
93         try {
94             return upload(filePart, false)
95         } catch (e: IOException) {
96             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
97                     "Error in Save CBA: ${e.message}", e)
98         }
99     }
100
101
102     /**
103      * This is a searchBlueprintModels method
104      *
105      * @param tags tags
106      * @return List<BlueprintModelSearch>
107     </BlueprintModelSearch> */
108     open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
109         return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
110     }
111
112     /**
113      * This is a getBlueprintModelSearchByNameAndVersion method
114      *
115      * @param name name
116      * @param version version
117      * @return BlueprintModelSearch
118      * @throws BluePrintException BluePrintException
119      */
120     @Throws(BluePrintException::class)
121     open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch {
122         return blueprintModelSearchRepository.findByArtifactNameAndArtifactVersion(name, version)
123                 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
124                         String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version))
125
126     }
127
128     /**
129      * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
130      *
131      * @param name name
132      * @param version version
133      * @return ResponseEntity<Resource>
134      * @throws BluePrintException BluePrintException
135     </Resource> */
136     @Throws(BluePrintException::class)
137     open fun downloadBlueprintModelFileByNameAndVersion(name: String,
138                                                         version: String): ResponseEntity<Resource> {
139         try {
140             val archiveByteArray = download(name, version)
141             val fileName = "${name}_$version.zip"
142             return prepareResourceEntity(fileName, archiveByteArray)
143         } catch (e: BluePrintException) {
144             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
145                     String.format("Error while " + "downloading the CBA file: %s", e.message), e)
146         }
147     }
148
149     /**
150      * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
151      *
152      * @return ResponseEntity<Resource>
153      * @throws BluePrintException BluePrintException
154     </Resource> */
155     @Throws(BluePrintException::class)
156     open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
157         val blueprintModel: BlueprintModel
158         try {
159             blueprintModel = getBlueprintModel(id)
160         } catch (e: BluePrintException) {
161             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
162         }
163
164         val fileName = "${blueprintModel.artifactName}_${blueprintModel.artifactVersion}.zip"
165         val file = blueprintModel.blueprintModelContent?.content
166                 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
167                         String.format("Error while downloading the CBA file: couldn't get model content"))
168         return prepareResourceEntity(fileName, file)
169     }
170
171     /**
172      * @return ResponseEntity<Resource>
173     </Resource> */
174     private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
175         return ResponseEntity.ok()
176                 .contentType(MediaType.parseMediaType("text/plain"))
177                 .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
178                 .body(ByteArrayResource(file))
179     }
180
181     /**
182      * This is a getBlueprintModel method
183      *
184      * @param id id
185      * @return BlueprintModel
186      * @throws BluePrintException BluePrintException
187      */
188     @Throws(BluePrintException::class)
189     open fun getBlueprintModel(id: String): BlueprintModel {
190         val blueprintModel: BlueprintModel
191         val dbBlueprintModel = blueprintModelRepository.findById(id)
192         if (dbBlueprintModel.isPresent) {
193             blueprintModel = dbBlueprintModel.get()
194         } else {
195             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
196             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
197         }
198         return blueprintModel
199     }
200
201     /**
202      * This is a getBlueprintModelByNameAndVersion method
203      *
204      * @param name name
205      * @param version version
206      * @return BlueprintModel
207      * @throws BluePrintException BluePrintException
208      */
209     @Throws(BluePrintException::class)
210     open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
211         val blueprintModel = blueprintModelRepository
212                 .findByArtifactNameAndArtifactVersion(name, version)
213         if (blueprintModel != null) {
214             return blueprintModel
215         } else {
216             val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
217             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
218         }
219     }
220
221     /**
222      * This is a getBlueprintModelSearch method
223      *
224      * @param id id
225      * @return BlueprintModelSearch
226      * @throws BluePrintException BluePrintException
227      */
228     @Throws(BluePrintException::class)
229     open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
230         return blueprintModelSearchRepository.findById(id)
231                 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
232                         String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id))
233     }
234
235     /**
236      * This is a searchBluePrintModelsByKeyWord method to retrieve specific  BlueprintModel in Database
237      * where keyword equals updatedBy or tags or artifcat name or artifcat version or artifact type
238      * @author Shaaban Ebrahim
239      * @param keyWord
240      *
241      * @return List<BlueprintModelSearch> list of the controller blueprint
242     </BlueprintModelSearch> */
243     open fun searchBluePrintModelsByKeyWord(keyWord: String): List<BlueprintModelSearch> {
244         return blueprintModelSearchRepository.
245                 findByUpdatedByOrTagsOrOrArtifactNameOrOrArtifactVersionOrArtifactType(
246                         keyWord,keyWord,keyWord,keyWord,keyWord)
247     }
248     
249     /**
250      * This is a deleteBlueprintModel method
251      *
252      * @param id id
253      * @throws BluePrintException BluePrintException
254      */
255     @Transactional
256     @Throws(BluePrintException::class)
257     open fun deleteBlueprintModel(id: String) {
258         val dbBlueprintModel = blueprintModelRepository.findById(id)
259         if (dbBlueprintModel != null && dbBlueprintModel.isPresent) {
260             blueprintModelContentRepository.deleteByBlueprintModel(dbBlueprintModel.get())
261             blueprintModelRepository.delete(dbBlueprintModel.get())
262         } else {
263             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
264             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
265         }
266     }
267
268     open suspend fun deleteBlueprintModel(name: String, version: String) {
269         blueprintsProcessorCatalogService.deleteFromDatabase(name, version)
270     }
271
272     /**
273      * This is a CBA enrichBlueprint method
274      * Save the Zip File in archive location and extract the cba content.
275      * Populate the Enhancement Location
276      * Enhance the CBA content
277      * Compress the Enhanced Content
278      * Return back the the compressed content back to the caller.
279      *
280      * @param filePart filePart
281      * @return ResponseEntity<Resource>
282      * @throws BluePrintException BluePrintException
283      */
284     @Throws(BluePrintException::class)
285     open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
286         try {
287             val enhancedByteArray = enrichBlueprintFileSource(filePart)
288             return BluePrintEnhancerUtils.prepareResourceEntity("enhanced-cba.zip", enhancedByteArray)
289         } catch (e: IOException) {
290             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
291                     "Error in Enriching CBA: ${e.message}", e)
292         }
293     }
294
295     /**
296      * This is a publishBlueprintModel method to change the status published to YES
297      *
298      * @param filePart filePart
299      * @return BlueprintModelSearch
300      * @throws BluePrintException BluePrintException
301      */
302     @Throws(BluePrintException::class)
303     open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
304         try {
305             return upload(filePart, true)
306         } catch (e: Exception) {
307             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
308                     "Error in Publishing CBA: ${e.message}", e)
309         }
310     }
311
312     /** Common CBA Save and Publish function for RestController and GRPC Handler, the [fileSource] may be
313      * byteArray or File Part type.*/
314     open suspend fun upload(fileSource: Any, validate: Boolean): BlueprintModelSearch {
315         val saveId = UUID.randomUUID().toString()
316         val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
317         val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId)
318         try {
319             val compressedFile = normalizedFile(blueprintArchive, "cba.zip")
320             when (fileSource) {
321                 is FilePart -> BluePrintEnhancerUtils.filePartAsFile(fileSource, compressedFile)
322                 is ByteArray -> BluePrintEnhancerUtils.byteArrayAsFile(fileSource, compressedFile)
323             }
324             // Save the Copied file to Database
325             val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate)
326
327             return blueprintModelSearchRepository.findById(blueprintId)
328                     ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
329                             String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
330
331         } catch (e: IOException) {
332             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
333                     "Error in Upload CBA: ${e.message}", e)
334         } finally {
335             // Clean blueprint script cache
336             val cacheKey = BluePrintFileUtils
337                     .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId))
338             BluePrintCompileCache.cleanClassLoader(cacheKey)
339             deleteNBDir(blueprintArchive)
340             deleteNBDir(blueprintWorking)
341         }
342     }
343
344     /** Common CBA download function for RestController and GRPC Handler, the [fileSource] may be
345      * byteArray or File Part type.*/
346     open fun download(name: String, version: String): ByteArray {
347         try {
348             val blueprintModel = getBlueprintModelByNameAndVersion(name, version)
349             return blueprintModel.blueprintModelContent?.content
350                     ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
351                             String.format("Error while downloading the CBA file: couldn't get model content"))
352         } catch (e: BluePrintException) {
353             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
354                     String.format("Error while " + "downloading the CBA file: %s", e.message), e)
355         }
356     }
357
358     /** Common CBA Enrich function for RestController and GRPC Handler, the [fileSource] may be
359      * byteArray or File Part type.*/
360     open suspend fun enrichBlueprintFileSource(fileSource: Any): ByteArray {
361         val enhanceId = UUID.randomUUID().toString()
362         val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
363         val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
364         try {
365             when (fileSource) {
366                 is FilePart -> BluePrintEnhancerUtils
367                         .copyFilePartToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
368                 is ByteArray -> BluePrintEnhancerUtils
369                         .copyByteArrayToEnhanceDir(fileSource, blueprintArchive, blueprintWorkingDir)
370             }            // Enhance the Blue Prints
371             bluePrintEnhancerService.enhance(blueprintWorkingDir)
372
373             return BluePrintEnhancerUtils.compressEnhanceDirAndReturnByteArray(blueprintWorkingDir, blueprintArchive)
374
375         } catch (e: IOException) {
376             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
377                     "Error in Enriching CBA: ${e.message}", e)
378         } finally {
379             BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
380         }
381     }
382
383     companion object {
384
385         private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
386         private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"
387     }
388 }