Merge "Fix errors in INFO.yaml"
[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.slf4j.LoggerFactory
33 import org.springframework.core.io.ByteArrayResource
34 import org.springframework.core.io.Resource
35 import org.springframework.http.HttpHeaders
36 import org.springframework.http.MediaType
37 import org.springframework.http.ResponseEntity
38 import org.springframework.http.codec.multipart.FilePart
39 import org.springframework.stereotype.Service
40 import org.springframework.transaction.annotation.Transactional
41 import java.io.File
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 controllerBlueprintsCatalogService: 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 = LoggerFactory.getLogger(BluePrintModelHandler::class.java)!!
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         val saveId = UUID.randomUUID().toString()
81         val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId)
82         try {
83             //Recreate the Dir
84             normalizedFile(bluePrintLoadConfiguration.blueprintArchivePath, saveId).reCreateDirs()
85             val deCompressedFile = normalizedFile(blueprintArchive, "cba.zip")
86             // Copy the File Part to Local File
87             BluePrintEnhancerUtils.copyFromFilePart(filePart, deCompressedFile)
88             // Save the Copied file to Database
89             val blueprintId = controllerBlueprintsCatalogService.saveToDatabase(saveId, deCompressedFile, false)
90             // Check and Return the Saved File
91             val blueprintModelSearch = blueprintModelSearchRepository.findById(blueprintId)
92                     ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
93                             String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
94
95             log.info("Save($saveId) successful for blueprint(${blueprintModelSearch.artifactName}) " +
96                     "version(${blueprintModelSearch.artifactVersion})")
97             return blueprintModelSearch
98         } catch (e: IOException) {
99             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
100                     "Error in Save CBA: ${e.message}", e)
101         } finally {
102             deleteDir(blueprintArchive)
103         }
104     }
105
106
107     /**
108      * This is a searchBlueprintModels method
109      *
110      * @param tags tags
111      * @return List<BlueprintModelSearch>
112     </BlueprintModelSearch> */
113     open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
114         return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
115     }
116
117     /**
118      * This is a getBlueprintModelSearchByNameAndVersion method
119      *
120      * @param name name
121      * @param version version
122      * @return BlueprintModelSearch
123      * @throws BluePrintException BluePrintException
124      */
125     @Throws(BluePrintException::class)
126     open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch {
127         return blueprintModelSearchRepository.findByArtifactNameAndArtifactVersion(name, version)
128                 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
129                         String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version))
130
131     }
132
133     /**
134      * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
135      *
136      * @param name name
137      * @param version version
138      * @return ResponseEntity<Resource>
139      * @throws BluePrintException BluePrintException
140     </Resource> */
141     @Throws(BluePrintException::class)
142     open fun downloadBlueprintModelFileByNameAndVersion(name: String,
143                                                         version: String): ResponseEntity<Resource> {
144         val blueprintModel: BlueprintModel
145         try {
146             blueprintModel = getBlueprintModelByNameAndVersion(name, version)
147         } catch (e: BluePrintException) {
148             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
149                     String.format("Error while " + "downloading the CBA file: %s", e.message), e)
150         }
151
152         val fileName = blueprintModel.id + ".zip"
153         val file = blueprintModel.blueprintModelContent?.content
154                 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
155                         String.format("Error while downloading the CBA file: couldn't get model content"))
156         return prepareResourceEntity(fileName, file)
157     }
158
159     /**
160      * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
161      *
162      * @return ResponseEntity<Resource>
163      * @throws BluePrintException BluePrintException
164     </Resource> */
165     @Throws(BluePrintException::class)
166     open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
167         val blueprintModel: BlueprintModel
168         try {
169             blueprintModel = getBlueprintModel(id)
170         } catch (e: BluePrintException) {
171             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
172         }
173
174         val fileName = blueprintModel.id + ".zip"
175         val file = blueprintModel.blueprintModelContent?.content
176                 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
177                         String.format("Error while downloading the CBA file: couldn't get model content"))
178         return prepareResourceEntity(fileName, file)
179     }
180
181     /**
182      * @return ResponseEntity<Resource>
183     </Resource> */
184     private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
185         return ResponseEntity.ok()
186                 .contentType(MediaType.parseMediaType("text/plain"))
187                 .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
188                 .body(ByteArrayResource(file))
189     }
190
191     /**
192      * This is a getBlueprintModel method
193      *
194      * @param id id
195      * @return BlueprintModel
196      * @throws BluePrintException BluePrintException
197      */
198     @Throws(BluePrintException::class)
199     open fun getBlueprintModel(id: String): BlueprintModel {
200         val blueprintModel: BlueprintModel
201         val dbBlueprintModel = blueprintModelRepository.findById(id)
202         if (dbBlueprintModel.isPresent) {
203             blueprintModel = dbBlueprintModel.get()
204         } else {
205             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
206             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
207         }
208         return blueprintModel
209     }
210
211     /**
212      * This is a getBlueprintModelByNameAndVersion method
213      *
214      * @param name name
215      * @param version version
216      * @return BlueprintModel
217      * @throws BluePrintException BluePrintException
218      */
219     @Throws(BluePrintException::class)
220     open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
221         val blueprintModel = blueprintModelRepository
222                 .findByArtifactNameAndArtifactVersion(name, version)
223         if (blueprintModel != null) {
224             return blueprintModel
225         } else {
226             val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
227             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
228         }
229     }
230
231     /**
232      * This is a getBlueprintModelSearch method
233      *
234      * @param id id
235      * @return BlueprintModelSearch
236      * @throws BluePrintException BluePrintException
237      */
238     @Throws(BluePrintException::class)
239     open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
240         return blueprintModelSearchRepository.findById(id)
241                 ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
242                         String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id))
243     }
244
245     /**
246      * This is a deleteBlueprintModel method
247      *
248      * @param id id
249      * @throws BluePrintException BluePrintException
250      */
251     @Transactional
252     @Throws(BluePrintException::class)
253     open fun deleteBlueprintModel(id: String) {
254         val dbBlueprintModel = blueprintModelRepository.findById(id)
255         if (dbBlueprintModel != null && dbBlueprintModel.isPresent) {
256             blueprintModelContentRepository.deleteByBlueprintModel(dbBlueprintModel.get())
257             blueprintModelRepository.delete(dbBlueprintModel.get())
258         } else {
259             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
260             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
261         }
262     }
263
264     /**
265      * This is a CBA enrichBlueprint method
266      * Save the Zip File in archive location and extract the cba content.
267      * Populate the Enhancement Location
268      * Enhance the CBA content
269      * Compress the Enhanced Content
270      * Return back the the compressed content back to the caller.
271      *
272      * @param filePart filePart
273      * @return ResponseEntity<Resource>
274      * @throws BluePrintException BluePrintException
275      */
276     @Throws(BluePrintException::class)
277     open suspend fun enrichBlueprint(filePart: FilePart): ResponseEntity<Resource> {
278         val enhanceId = UUID.randomUUID().toString()
279         val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, enhanceId)
280         val blueprintWorkingDir = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, enhanceId)
281         try {
282             BluePrintEnhancerUtils.decompressFilePart(filePart, blueprintArchive, blueprintWorkingDir)
283
284             // Enhance the Blue Prints
285             bluePrintEnhancerService.enhance(blueprintWorkingDir)
286
287             return BluePrintEnhancerUtils.compressToFilePart(blueprintWorkingDir, blueprintArchive)
288
289         } catch (e: IOException) {
290             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
291                     "Error in Enriching CBA: ${e.message}", e)
292         } finally {
293             BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
294         }
295     }
296
297     /**
298      * This is a publishBlueprintModel method to change the status published to YES
299      *
300      * @param filePart filePart
301      * @return BlueprintModelSearch
302      * @throws BluePrintException BluePrintException
303      */
304     @Throws(BluePrintException::class)
305     open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch {
306         val publishId = UUID.randomUUID().toString()
307         val blueprintArchive = bluePrintLoadConfiguration.blueprintArchivePath.plus(File.separator).plus(publishId)
308         val blueprintWorkingDir = bluePrintLoadConfiguration.blueprintWorkingPath.plus(File.separator).plus(publishId)
309         try {
310             val compressedFilePart = BluePrintEnhancerUtils
311                     .extractCompressFilePart(filePart, blueprintArchive, blueprintWorkingDir)
312
313             val blueprintId = controllerBlueprintsCatalogService.saveToDatabase(publishId, compressedFilePart, true)
314
315             return blueprintModelSearchRepository.findById(blueprintId)
316                     ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
317                             String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId))
318
319         } catch (e: Exception) {
320             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
321                     "Error in Publishing CBA: ${e.message}", e)
322         } finally {
323             BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir)
324         }
325     }
326
327     companion object {
328
329         private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
330         private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"
331     }
332 }