Change SQL query syntax for delete resource/template
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / db / ResourceResolutionDBService.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.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
25 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
26 import org.slf4j.LoggerFactory
27 import org.springframework.dao.EmptyResultDataAccessException
28 import org.springframework.stereotype.Service
29 import java.lang.IllegalArgumentException
30 import java.util.UUID
31
32 @Service
33 class ResourceResolutionDBService(private val resourceResolutionRepository: ResourceResolutionRepository) {
34
35     private val log = LoggerFactory.getLogger(ResourceResolutionDBService::class.toString())
36
37     suspend fun findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence(
38         bluePrintRuntimeService: BluePrintRuntimeService<*>,
39         key: String,
40         occurrence: Int,
41         artifactPrefix: String
42     ): List<ResourceResolution> {
43         return try {
44             val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
45
46             val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
47             val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
48
49             resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence(
50                 blueprintName,
51                 blueprintVersion,
52                 artifactPrefix,
53                 key,
54                 occurrence
55             )
56         } catch (e: EmptyResultDataAccessException) {
57             emptyList()
58         }
59     }
60
61     suspend fun findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence(
62         bluePrintRuntimeService: BluePrintRuntimeService<*>,
63         resourceId: String,
64         resourceType: String,
65         occurrence: Int,
66         artifactPrefix: String
67     ): List<ResourceResolution> {
68         return try {
69
70             val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
71
72             val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
73             val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
74
75             resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence(
76                 blueprintName,
77                 blueprintVersion,
78                 artifactPrefix,
79                 resourceId,
80                 resourceType,
81                 occurrence
82             )
83         } catch (e: EmptyResultDataAccessException) {
84             emptyList()
85         }
86     }
87
88     suspend fun readValue(
89         blueprintName: String,
90         blueprintVersion: String,
91         artifactPrefix: String,
92         resolutionKey: String,
93         name: String
94     ): ResourceResolution? = withContext(Dispatchers.IO) {
95
96         resourceResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndName(
97             resolutionKey,
98             blueprintName,
99             blueprintVersion,
100             artifactPrefix,
101             name
102         )
103     }
104
105     suspend fun readWithResolutionKey(
106         blueprintName: String,
107         blueprintVersion: String,
108         artifactPrefix: String,
109         resolutionKey: String
110     ): List<ResourceResolution> = withContext(Dispatchers.IO) {
111
112         resourceResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
113             resolutionKey,
114             blueprintName,
115             blueprintVersion,
116             artifactPrefix
117         )
118     }
119
120     /**
121      * This returns the resolutions of first N 'occurrences'.
122      *
123      * @param blueprintName
124      * @param blueprintVersion
125      * @param artifactPrefix
126      * @param resolutionKey
127      * @param firstN
128      */
129     suspend fun findFirstNOccurrences(
130         blueprintName: String,
131         blueprintVersion: String,
132         artifactPrefix: String,
133         resolutionKey: String,
134         firstN: Int
135     ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) {
136
137         resourceResolutionRepository.findFirstNOccurrences(
138             resolutionKey,
139             blueprintName,
140             blueprintVersion,
141             artifactPrefix,
142             firstN
143         ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder())
144     }
145
146     /**
147      * This returns the resolutions of last N 'occurrences'.
148      *
149      * @param blueprintName
150      * @param blueprintVersion
151      * @param artifactPrefix
152      * @param resolutionKey
153      * @param lastN
154      */
155     suspend fun findLastNOccurrences(
156         blueprintName: String,
157         blueprintVersion: String,
158         artifactPrefix: String,
159         resolutionKey: String,
160         lastN: Int
161     ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) {
162
163         resourceResolutionRepository.findLastNOccurrences(
164             resolutionKey,
165             blueprintName,
166             blueprintVersion,
167             artifactPrefix,
168             lastN
169         ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder())
170     }
171
172     /**
173      * This returns the resolutions with 'occurrence' value between begin and end.
174      *
175      * @param blueprintName
176      * @param blueprintVersion
177      * @param artifactPrefix
178      * @param resolutionKey
179      * @param begin
180      * @param end
181      */
182     suspend fun findOccurrencesWithinRange(
183         blueprintName: String,
184         blueprintVersion: String,
185         artifactPrefix: String,
186         resolutionKey: String,
187         begin: Int,
188         end: Int
189     ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) {
190
191         resourceResolutionRepository.findOccurrencesWithinRange(
192             resolutionKey,
193             blueprintName,
194             blueprintVersion,
195             artifactPrefix,
196             begin,
197             end
198         ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder())
199     }
200
201     suspend fun readWithResourceIdAndResourceType(
202         blueprintName: String,
203         blueprintVersion: String,
204         resourceId: String,
205         resourceType: String
206     ): List<ResourceResolution> =
207         withContext(Dispatchers.IO) {
208
209             resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType(
210                 blueprintName,
211                 blueprintVersion,
212                 resourceId,
213                 resourceType
214             )
215         }
216
217     suspend fun write(
218         properties: Map<String, Any>,
219         bluePrintRuntimeService: BluePrintRuntimeService<*>,
220         artifactPrefix: String,
221         resourceAssignment: ResourceAssignment
222     ): ResourceResolution = withContext(Dispatchers.IO) {
223
224         val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
225
226         val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
227         val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
228
229         val resolutionKey = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] as String
230         val resourceId = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] as String
231         val resourceType = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] as String
232         val occurrence = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int
233
234         write(
235             blueprintName,
236             blueprintVersion,
237             resolutionKey,
238             resourceId,
239             resourceType,
240             artifactPrefix,
241             resourceAssignment,
242             occurrence
243         )
244     }
245
246     suspend fun write(
247         blueprintName: String,
248         blueprintVersion: String,
249         resolutionKey: String,
250         resourceId: String,
251         resourceType: String,
252         artifactPrefix: String,
253         resourceAssignment: ResourceAssignment,
254         occurrence: Int = 0
255     ): ResourceResolution = withContext(Dispatchers.IO) {
256
257         val resourceResolution = ResourceResolution()
258         resourceResolution.id = UUID.randomUUID().toString()
259         resourceResolution.artifactName = artifactPrefix
260         resourceResolution.occurrence = occurrence
261         resourceResolution.blueprintVersion = blueprintVersion
262         resourceResolution.blueprintName = blueprintName
263         resourceResolution.resolutionKey = resolutionKey
264         resourceResolution.resourceType = resourceType
265         resourceResolution.resourceId = resourceId
266         resourceResolution.value = resourceAssignment.property?.value?.let {
267             if (BluePrintConstants.STATUS_SUCCESS == resourceAssignment.status)
268                 JacksonUtils.getValue(it).toString()
269             else ""
270         } ?: ""
271         resourceResolution.name = resourceAssignment.name
272         resourceResolution.dictionaryName = resourceAssignment.dictionaryName
273         resourceResolution.dictionaryVersion = resourceAssignment.version
274         resourceResolution.dictionarySource = resourceAssignment.dictionarySource
275         resourceResolution.status = resourceAssignment.status ?: BluePrintConstants.STATUS_FAILURE
276
277         try {
278             resourceResolutionRepository.saveAndFlush(resourceResolution)
279         } catch (ex: Exception) {
280             throw BluePrintException("Failed to store resource resolution result.", ex)
281         }
282     }
283
284     /**
285      * This method to deletes resources associated to a specific resolution-key
286      *
287      * @param blueprintName name of the CBA
288      * @param blueprintVersion version of the CBA
289      * @param artifactName name of the artifact
290      * @param resolutionKey value of the resolution-key
291      * @param lastNOccurrences number of occurrences to delete starting from the last,
292      * all occurrences will be deleted when null
293      *
294      * @return number of deleted rows
295      */
296     fun deleteResources(
297         blueprintName: String,
298         blueprintVersion: String,
299         artifactName: String,
300         resolutionKey: String,
301         lastNOccurrences: Int?
302     ): Int = lastNOccurrences?.let {
303         if (lastNOccurrences < 0) {
304             throw IllegalArgumentException("last N occurrences must be a positive integer")
305         }
306         resourceResolutionRepository.deleteLastNOccurrences(
307             blueprintName,
308             blueprintVersion,
309             artifactName,
310             resolutionKey,
311             it
312         )
313     } ?: resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
314         blueprintName,
315         blueprintVersion,
316         artifactName,
317         resolutionKey
318     )
319
320     /**
321      * This method to deletes resources associated to a specific resourceType and resourceId
322      *
323      * @param blueprintName name of the CBA
324      * @param blueprintVersion version of the CBA
325      * @param artifactName name of the artifact
326      * @param resourceType value of the resourceType
327      * @param resourceId value of the resourceId
328      * @param lastNOccurrences number of occurrences to delete starting from the last,
329      * all occurrences will be deleted when null
330      *
331      * @return number of deleted rows
332      */
333     fun deleteResources(
334         blueprintName: String,
335         blueprintVersion: String,
336         artifactName: String,
337         resourceType: String,
338         resourceId: String,
339         lastNOccurrences: Int?
340     ): Int = lastNOccurrences?.let {
341         if (lastNOccurrences < 0) {
342             throw IllegalArgumentException("last N occurrences must be a positive integer")
343         }
344         resourceResolutionRepository.deleteLastNOccurrences(
345             blueprintName,
346             blueprintVersion,
347             artifactName,
348             resourceType,
349             resourceId,
350             it
351         )
352     } ?: resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceTypeAndResourceId(
353         blueprintName,
354         blueprintVersion,
355         artifactName,
356         resourceType,
357         resourceId
358     )
359
360     suspend fun deleteResourceResolutionList(listResourceResolution: List<ResourceResolution>) = withContext(Dispatchers.IO) {
361         try {
362             resourceResolutionRepository.deleteInBatch(listResourceResolution)
363         } catch (ex: Exception) {
364             throw BluePrintException("Failed to batch delete resource resolution", ex)
365         }
366     }
367
368     /**
369      * This method returns the (highest occurrence + 1) of resource resolutions if present in DB, returns 1 otherwise.
370      * The 'occurrence' is used to persist new resource resolution in the DB.
371      *
372      * @param resolutionKey
373      * @param blueprintName
374      * @param blueprintVersion
375      * @param artifactPrefix
376      */
377     suspend fun findNextOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
378         resolutionKey: String,
379         blueprintName: String,
380         blueprintVersion: String,
381         artifactPrefix: String
382     ) = withContext(Dispatchers.IO) {
383         val maxOccurrence = resourceResolutionRepository.findMaxOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
384             resolutionKey,
385             blueprintName,
386             blueprintVersion,
387             artifactPrefix
388         )
389         maxOccurrence?.inc() ?: 1
390     }
391
392     /**
393      * This method returns the (highest occurrence + 1) of resource resolutions if present in DB, returns 1 otherwise.
394      * The 'occurrence' is used to persist new resource resolution in the DB.
395      *
396      * @param blueprintName
397      * @param blueprintVersion
398      * @param resourceId
399      * @param resourceType
400      */
401     suspend fun findNextOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType(
402         blueprintName: String,
403         blueprintVersion: String,
404         resourceId: String,
405         resourceType: String
406     ) = withContext(Dispatchers.IO) {
407         val maxOccurrence = resourceResolutionRepository.findMaxOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType(
408             blueprintName,
409             blueprintVersion,
410             resourceId,
411             resourceType
412         )
413         maxOccurrence?.inc() ?: 1
414     }
415 }