Migrate "ms/controllerblueprints" from ccsdk/apps
[ccsdk/cds.git] / ms / controllerblueprints / modules / service / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / service / 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.controllerblueprints.service.handler
20
21 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
22 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
23 import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode
24 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService
25 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintEnhancerService
26 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
27 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils
28 import org.onap.ccsdk.cds.controllerblueprints.service.domain.BlueprintModel
29 import org.onap.ccsdk.cds.controllerblueprints.service.domain.BlueprintModelSearch
30 import org.onap.ccsdk.cds.controllerblueprints.service.repository.ControllerBlueprintModelContentRepository
31 import org.onap.ccsdk.cds.controllerblueprints.service.repository.ControllerBlueprintModelRepository
32 import org.onap.ccsdk.cds.controllerblueprints.service.repository.ControllerBlueprintModelSearchRepository
33 import org.onap.ccsdk.cds.controllerblueprints.service.utils.BluePrintEnhancerUtils
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 reactor.core.publisher.Mono
43 import java.io.File
44 import java.io.IOException
45 import java.util.*
46
47 /**
48  * BlueprintModelHandler Purpose: Handler service to handle the request from BlurPrintModelRest
49  *
50  * @author Brinda Santh
51  * @version 1.0
52  */
53
54 @Service
55 open class BluePrintModelHandler(private val bluePrintCatalogService: BluePrintCatalogService,
56                                  private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
57                                  private val blueprintModelSearchRepository: ControllerBlueprintModelSearchRepository,
58                                  private val blueprintModelRepository: ControllerBlueprintModelRepository,
59                                  private val blueprintModelContentRepository: ControllerBlueprintModelContentRepository,
60                                  private val bluePrintEnhancerService: BluePrintEnhancerService) {
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 fun saveBlueprintModel(filePart: FilePart): Mono<BlueprintModelSearch> {
80         try {
81             val cbaLocation = BluePrintFileUtils.getCbaStorageDirectory(bluePrintLoadConfiguration.blueprintArchivePath)
82             return BluePrintEnhancerUtils.saveCBAFile(filePart, cbaLocation).map { fileName ->
83                 var blueprintId: String? = null
84                 try {
85                     blueprintId = bluePrintCatalogService.saveToDatabase(cbaLocation.resolve(fileName).toFile(), false)
86                 } catch (e: BluePrintException) {
87                     // FIXME handle expection
88                 }
89                 blueprintModelSearchRepository.findById(blueprintId!!).get()
90             }
91         } catch (e: IOException) {
92             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
93                     String.format("I/O Error while uploading the CBA file: %s", e.message), e)
94         }
95
96     }
97
98
99     /**
100      * This is a searchBlueprintModels method
101      *
102      * @param tags tags
103      * @return List<BlueprintModelSearch>
104     </BlueprintModelSearch> */
105     open fun searchBlueprintModels(tags: String): List<BlueprintModelSearch> {
106         return blueprintModelSearchRepository.findByTagsContainingIgnoreCase(tags)
107     }
108
109     /**
110      * This is a getBlueprintModelSearchByNameAndVersion method
111      *
112      * @param name name
113      * @param version version
114      * @return BlueprintModelSearch
115      * @throws BluePrintException BluePrintException
116      */
117     @Throws(BluePrintException::class)
118     open fun getBlueprintModelSearchByNameAndVersion(name: String, version: String): BlueprintModelSearch {
119         val blueprintModelSearch: BlueprintModelSearch
120         val dbBlueprintModel = blueprintModelSearchRepository
121                 .findByArtifactNameAndArtifactVersion(name, version)
122         if (dbBlueprintModel.isPresent) {
123             blueprintModelSearch = dbBlueprintModel.get()
124         } else {
125             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value,
126                     String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version))
127         }
128         return blueprintModelSearch
129     }
130
131     /**
132      * This is a downloadBlueprintModelFileByNameAndVersion method to download a Blueprint by Name and Version
133      *
134      * @param name name
135      * @param version version
136      * @return ResponseEntity<Resource>
137      * @throws BluePrintException BluePrintException
138     </Resource> */
139     @Throws(BluePrintException::class)
140     open fun downloadBlueprintModelFileByNameAndVersion(name: String,
141                                                         version: String): ResponseEntity<Resource> {
142         val blueprintModel: BlueprintModel
143         try {
144             blueprintModel = getBlueprintModelByNameAndVersion(name, version)
145         } catch (e: BluePrintException) {
146             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
147         }
148
149         val fileName = blueprintModel.id + ".zip"
150         val file = blueprintModel.blueprintModelContent.content
151         return prepareResourceEntity(fileName, file)
152     }
153
154     /**
155      * This is a downloadBlueprintModelFile method to find the target file to download and return a file resource
156      *
157      * @return ResponseEntity<Resource>
158      * @throws BluePrintException BluePrintException
159     </Resource> */
160     @Throws(BluePrintException::class)
161     open fun downloadBlueprintModelFile(id: String): ResponseEntity<Resource> {
162         val blueprintModel: BlueprintModel
163         try {
164             blueprintModel = getBlueprintModel(id)
165         } catch (e: BluePrintException) {
166             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format("Error while " + "downloading the CBA file: %s", e.message), e)
167         }
168
169         val fileName = blueprintModel.id + ".zip"
170         val file = blueprintModel.blueprintModelContent.content
171         return prepareResourceEntity(fileName, file)
172     }
173
174     /**
175      * @return ResponseEntity<Resource>
176     </Resource> */
177     private fun prepareResourceEntity(fileName: String, file: ByteArray): ResponseEntity<Resource> {
178         return ResponseEntity.ok()
179                 .contentType(MediaType.parseMediaType("text/plain"))
180                 .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$fileName\"")
181                 .body(ByteArrayResource(file))
182     }
183
184     /**
185      * This is a getBlueprintModel method
186      *
187      * @param id id
188      * @return BlueprintModel
189      * @throws BluePrintException BluePrintException
190      */
191     @Throws(BluePrintException::class)
192     open fun getBlueprintModel(id: String): BlueprintModel {
193         val blueprintModel: BlueprintModel
194         val dbBlueprintModel = blueprintModelRepository.findById(id)
195         if (dbBlueprintModel.isPresent) {
196             blueprintModel = dbBlueprintModel.get()
197         } else {
198             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
199             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
200         }
201         return blueprintModel
202     }
203
204     /**
205      * This is a getBlueprintModelByNameAndVersion method
206      *
207      * @param name name
208      * @param version version
209      * @return BlueprintModel
210      * @throws BluePrintException BluePrintException
211      */
212     @Throws(BluePrintException::class)
213     open fun getBlueprintModelByNameAndVersion(name: String, version: String): BlueprintModel {
214         val blueprintModel = blueprintModelRepository
215                 .findByArtifactNameAndArtifactVersion(name, version)
216         if (blueprintModel != null) {
217             return blueprintModel
218         } else {
219             val msg = String.format(BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG, name, version)
220             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
221         }
222     }
223
224     /**
225      * This is a getBlueprintModelSearch method
226      *
227      * @param id id
228      * @return BlueprintModelSearch
229      * @throws BluePrintException BluePrintException
230      */
231     @Throws(BluePrintException::class)
232     open fun getBlueprintModelSearch(id: String): BlueprintModelSearch {
233         val blueprintModelSearch: BlueprintModelSearch
234         val dbBlueprintModel = blueprintModelSearchRepository.findById(id)
235         if (dbBlueprintModel.isPresent) {
236             blueprintModelSearch = dbBlueprintModel.get()
237         } else {
238             val msg = String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, id)
239             throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, msg)
240         }
241
242         return blueprintModelSearch
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.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 blueprintEnrichmentDir = normalizedPathName(bluePrintLoadConfiguration.blueprintEnrichmentPath, enhanceId)
281         try {
282             BluePrintEnhancerUtils.decompressFilePart(filePart, blueprintArchive, blueprintEnrichmentDir)
283
284             // Enhance the Blue Prints
285             bluePrintEnhancerService.enhance(blueprintEnrichmentDir)
286
287             return BluePrintEnhancerUtils.compressToFilePart(blueprintEnrichmentDir, 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, blueprintEnrichmentDir)
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 blueprintEnrichmentDir = bluePrintLoadConfiguration.blueprintEnrichmentPath.plus(File.separator).plus(publishId)
309         try {
310             val compressedFilePart = BluePrintEnhancerUtils
311                     .extractCompressFilePart(filePart, blueprintArchive, blueprintEnrichmentDir)
312
313             val blueprintId = bluePrintCatalogService.saveToDatabase(compressedFilePart, true)
314
315             return blueprintModelSearchRepository.findById(blueprintId).get()
316
317         } catch (e: Exception) {
318             throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value,
319                     "Error in Publishing CBA: ${e.message}", e)
320         } finally {
321             BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintEnrichmentDir)
322         }
323     }
324
325     companion object {
326
327         private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo"
328         private const val BLUEPRINT_MODEL_NAME_VERSION_FAILURE_MSG = "failed to get blueprint model by name(%s)" + " and version(%s) from repo"
329     }
330 }