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