Add endpoint for deleting templates
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / db / TemplateResolutionService.kt
1 /*
2  * Copyright (C) 2019 Bell Canada.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db
17
18 import kotlinx.coroutines.Dispatchers
19 import kotlinx.coroutines.withContext
20 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants
21 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
22 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
23 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
24 import org.slf4j.LoggerFactory
25 import org.springframework.dao.DataIntegrityViolationException
26 import org.springframework.dao.EmptyResultDataAccessException
27 import org.springframework.stereotype.Service
28 import java.lang.IllegalArgumentException
29 import java.util.UUID
30
31 @Service
32 class TemplateResolutionService(private val templateResolutionRepository: TemplateResolutionRepository) {
33
34     private val log = LoggerFactory.getLogger(TemplateResolutionService::class.toString())
35
36     suspend fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
37         bluePrintRuntimeService: BluePrintRuntimeService<*>,
38         artifactPrefix: String,
39         resolutionKey: String
40     ): String =
41         withContext(Dispatchers.IO) {
42
43             val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
44
45             val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
46             val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
47
48             findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
49                 blueprintName,
50                 blueprintVersion,
51                 artifactPrefix,
52                 resolutionKey
53             )
54         }
55
56     suspend fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
57         blueprintName: String,
58         blueprintVersion: String,
59         artifactPrefix: String,
60         resolutionKey: String,
61         occurrence: Int = 1
62     ): String =
63         withContext(Dispatchers.IO) {
64
65             templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence(
66                 resolutionKey,
67                 blueprintName,
68                 blueprintVersion,
69                 artifactPrefix,
70                 occurrence
71             )?.result ?: throw EmptyResultDataAccessException(1)
72         }
73
74     suspend fun findResolutionKeysByBlueprintNameAndBlueprintVersionAndArtifactName(
75         bluePrintRuntimeService: BluePrintRuntimeService<*>,
76         artifactPrefix: String,
77         occurrence: Int = 1
78     ): List<String> =
79         withContext(Dispatchers.IO) {
80
81             val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
82
83             val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
84             val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
85
86             templateResolutionRepository.findResolutionKeysByBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence(
87                 blueprintName,
88                 blueprintVersion,
89                 artifactPrefix,
90                 occurrence
91             ) ?: throw EmptyResultDataAccessException(1)
92         }
93
94     suspend fun findArtifactNamesAndResolutionKeysByBlueprintNameAndBlueprintVersion(
95         bluePrintRuntimeService: BluePrintRuntimeService<*>,
96         occurrence: Int = 1
97     ): Map<String, List<String>> =
98         withContext(Dispatchers.IO) {
99
100             val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
101
102             val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
103             val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
104
105             val resultList = templateResolutionRepository.findArtifactNamesAndResolutionKeysByBlueprintNameAndBlueprintVersionAndOccurrence(
106                 blueprintName,
107                 blueprintVersion,
108                 occurrence
109             ) ?: throw EmptyResultDataAccessException(1)
110
111             var resultMap: MutableMap<String, MutableList<String>> = mutableMapOf()
112
113             resultList.forEach { it ->
114                 if (!resultMap.containsKey(it.getArtifactName())) {
115                     resultMap[it.getArtifactName()] = mutableListOf(it.getResolutionKey())
116                 } else {
117                     resultMap[it.getArtifactName()]!!.add(it.getResolutionKey())
118                 }
119             }
120             resultMap
121                 .mapValues { it.value.toList() }
122                 .toMap()
123         }
124
125     suspend fun findByResoureIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactName(
126         blueprintName: String,
127         blueprintVersion: String,
128         artifactPrefix: String,
129         resourceId: String,
130         resourceType: String,
131         occurrence: Int = 1
132     ): String =
133         withContext(Dispatchers.IO) {
134
135             templateResolutionRepository.findByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence(
136                 resourceId,
137                 resourceType,
138                 blueprintName,
139                 blueprintVersion,
140                 artifactPrefix,
141                 occurrence
142             )?.result!!
143         }
144
145     suspend fun write(
146         properties: Map<String, Any>,
147         result: String,
148         bluePrintRuntimeService: BluePrintRuntimeService<*>,
149         artifactPrefix: String
150     ): TemplateResolution = withContext(Dispatchers.IO) {
151
152         val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
153
154         val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
155         val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
156         val resolutionKey = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] as String
157         val resourceId = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] as String
158         val resourceType = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] as String
159         val occurrence = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int
160         write(
161             blueprintName,
162             blueprintVersion,
163             artifactPrefix,
164             result,
165             occurrence,
166             resolutionKey,
167             resourceId,
168             resourceType
169         )
170     }
171
172     suspend fun write(
173         blueprintName: String,
174         blueprintVersion: String,
175         artifactPrefix: String,
176         template: String,
177         occurrence: Int = 1,
178         resolutionKey: String = "",
179         resourceId: String = "",
180         resourceType: String = ""
181     ): TemplateResolution =
182         withContext(Dispatchers.IO) {
183
184             val resourceResolutionResult = TemplateResolution()
185             resourceResolutionResult.id = UUID.randomUUID().toString()
186             resourceResolutionResult.artifactName = artifactPrefix
187             resourceResolutionResult.blueprintVersion = blueprintVersion
188             resourceResolutionResult.blueprintName = blueprintName
189             resourceResolutionResult.resolutionKey = resolutionKey
190             resourceResolutionResult.resourceId = resourceId
191             resourceResolutionResult.resourceType = resourceType
192             resourceResolutionResult.result = template
193             resourceResolutionResult.occurrence = occurrence
194
195             // Overwrite template resolution-key of resourceId/resourceType already existant
196             if (resolutionKey.isNotEmpty()) {
197                 templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence(
198                     resolutionKey, blueprintName, blueprintVersion, artifactPrefix, occurrence
199                 )?.let {
200                     log.info(
201                         "Overwriting template resolution for blueprintName=($blueprintVersion), blueprintVersion=($blueprintName), " +
202                             "artifactName=($artifactPrefix) and resolutionKey=($resolutionKey)"
203                     )
204                     templateResolutionRepository.deleteByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence(
205                         resolutionKey,
206                         blueprintName,
207                         blueprintVersion,
208                         artifactPrefix,
209                         occurrence
210                     )
211                 }
212             } else if (resourceId.isNotEmpty() && resourceType.isNotEmpty()) {
213                 templateResolutionRepository.findByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence(
214                     resourceId, resourceType, blueprintName, blueprintVersion, artifactPrefix, occurrence
215                 )?.let {
216                     log.info(
217                         "Overwriting template resolution for blueprintName=($blueprintVersion), blueprintVersion=($blueprintName), " +
218                             "artifactName=($artifactPrefix), resourceId=($resourceId) and resourceType=($resourceType)"
219                     )
220                     templateResolutionRepository.deleteByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactNameAndOccurrence(
221                         resourceId,
222                         resourceType,
223                         blueprintName,
224                         blueprintVersion,
225                         artifactPrefix,
226                         occurrence
227                     )
228                 }
229             }
230             try {
231                 log.info(
232                     "Writing out template_resolution result: bpName: $blueprintName bpVer $blueprintVersion resKey:$resolutionKey" +
233                         " (resourceId: $resourceId resourceType: $resourceType) occurrence:$occurrence"
234                 )
235                 templateResolutionRepository.saveAndFlush(resourceResolutionResult)
236             } catch (ex: DataIntegrityViolationException) {
237                 log.error(
238                     "Error writing out template_resolution result: bpName: $blueprintName bpVer $blueprintVersion resKey:$resolutionKey" +
239                         " (resourceId: $resourceId resourceType: $resourceType) occurrence:$occurrence error: {}",
240                     ex.message
241                 )
242                 throw BluePrintException("Failed to store resource api result.", ex)
243             }
244         }
245     /**
246      * This returns the templates of first N 'occurrences'.
247      *
248      * @param blueprintName
249      * @param blueprintVersion
250      * @param artifactPrefix
251      * @param resolutionKey
252      * @param firstN
253      */
254     suspend fun findFirstNOccurrences(
255         blueprintName: String,
256         blueprintVersion: String,
257         artifactPrefix: String,
258         resolutionKey: String,
259         firstN: Int
260     ): Map<Int, List<TemplateResolution>> = withContext(Dispatchers.IO) {
261
262         templateResolutionRepository.findFirstNOccurrences(
263             resolutionKey,
264             blueprintName,
265             blueprintVersion,
266             artifactPrefix,
267             firstN
268         ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder())
269     }
270
271     /**
272      * This returns the templates of last N 'occurrences'.
273      *
274      * @param blueprintName
275      * @param blueprintVersion
276      * @param artifactPrefix
277      * @param resolutionKey
278      * @param lastN
279      */
280     suspend fun findLastNOccurrences(
281         blueprintName: String,
282         blueprintVersion: String,
283         artifactPrefix: String,
284         resolutionKey: String,
285         lastN: Int
286     ): Map<Int, List<TemplateResolution>> = withContext(Dispatchers.IO) {
287
288         templateResolutionRepository.findLastNOccurrences(
289             resolutionKey,
290             blueprintName,
291             blueprintVersion,
292             artifactPrefix,
293             lastN
294         ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder())
295     }
296
297     /**
298      * This returns the templates with 'occurrence' value between begin and end.
299      *
300      * @param blueprintName
301      * @param blueprintVersion
302      * @param artifactPrefix
303      * @param resolutionKey
304      * @param begin
305      * @param end
306      */
307     suspend fun findOccurrencesWithinRange(
308         blueprintName: String,
309         blueprintVersion: String,
310         artifactPrefix: String,
311         resolutionKey: String,
312         begin: Int,
313         end: Int
314     ): Map<Int, List<TemplateResolution>> = withContext(Dispatchers.IO) {
315
316         templateResolutionRepository.findOccurrencesWithinRange(
317             resolutionKey,
318             blueprintName,
319             blueprintVersion,
320             artifactPrefix,
321             begin,
322             end
323         ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder())
324     }
325
326     suspend fun readWithResolutionKey(
327         blueprintName: String,
328         blueprintVersion: String,
329         artifactPrefix: String,
330         resolutionKey: String
331     ): List<TemplateResolution> = withContext(Dispatchers.IO) {
332
333         templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
334             resolutionKey,
335             blueprintName,
336             blueprintVersion,
337             artifactPrefix
338         )
339     }
340
341     suspend fun deleteTemplates(
342         blueprintName: String,
343         blueprintVersion: String,
344         artifactPrefix: String,
345         resolutionKey: String,
346         lastNOccurrences: Int?
347     ): Int = lastNOccurrences?.let {
348         if (lastNOccurrences < 0) {
349             throw IllegalArgumentException("last N occurrences must be a positive integer")
350         }
351         templateResolutionRepository.deleteTemplates(
352             blueprintName,
353             blueprintVersion,
354             artifactPrefix,
355             resolutionKey,
356             it
357         )
358     } ?: templateResolutionRepository.deleteByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
359         resolutionKey,
360         blueprintName,
361         blueprintVersion,
362         artifactPrefix
363     )
364
365     suspend fun deleteTemplates(
366         blueprintName: String,
367         blueprintVersion: String,
368         artifactPrefix: String,
369         resourceType: String,
370         resourceId: String,
371         lastNOccurrences: Int?
372     ): Int = lastNOccurrences?.let {
373         if (lastNOccurrences < 0) {
374             throw IllegalArgumentException("last N occurrences must be a positive integer")
375         }
376         templateResolutionRepository.deleteTemplates(
377             blueprintName,
378             blueprintVersion,
379             artifactPrefix,
380             resourceType,
381             resourceId,
382             it
383         )
384     } ?: templateResolutionRepository.deleteByResourceIdAndResourceTypeAndBlueprintNameAndBlueprintVersionAndArtifactName(
385         resourceId,
386         resourceType,
387         blueprintName,
388         blueprintVersion,
389         artifactPrefix
390     )
391 }