Merge "Fix swagger definition for blueprint processor"
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / ResourceResolutionService.kt
1 /*
2  *  Copyright © 2017-2018 AT&T Intellectual Property.
3  *  Modifications Copyright © 2018-2019 IBM, Bell Canada
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution
19
20 import kotlinx.coroutines.async
21 import kotlinx.coroutines.awaitAll
22 import kotlinx.coroutines.coroutineScope
23 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionDBService
24 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.TemplateResolutionService
25 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.ResourceAssignmentProcessor
26 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
27 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
28 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
29 import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
30 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
31 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintTemplateService
32 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
33 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
34 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceDefinition
35 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.utils.BulkResourceSequencingUtils
36 import org.slf4j.LoggerFactory
37 import org.springframework.context.ApplicationContext
38 import org.springframework.stereotype.Service
39
40 interface ResourceResolutionService {
41
42     fun registeredResourceSources(): List<String>
43
44     suspend fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>, artifactTemplate: String,
45                                     resolutionKey: String): String
46
47     suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
48                                  artifactNames: List<String>, properties: Map<String, Any>): MutableMap<String, String>
49
50     suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
51                                  artifactPrefix: String, properties: Map<String, Any>): String
52
53     suspend fun resolveResourceAssignments(blueprintRuntimeService: BluePrintRuntimeService<*>,
54                                            resourceDefinitions: MutableMap<String, ResourceDefinition>,
55                                            resourceAssignments: MutableList<ResourceAssignment>,
56                                            artifactPrefix: String,
57                                            properties: Map<String, Any>)
58 }
59
60 @Service(ResourceResolutionConstants.SERVICE_RESOURCE_RESOLUTION)
61 open class ResourceResolutionServiceImpl(private var applicationContext: ApplicationContext,
62                                          private var resolutionResultService: TemplateResolutionService,
63                                          private var blueprintTemplateService: BluePrintTemplateService,
64                                          private var resourceResolutionDBService: ResourceResolutionDBService) :
65     ResourceResolutionService {
66
67     private val log = LoggerFactory.getLogger(ResourceResolutionService::class.java)
68
69     override fun registeredResourceSources(): List<String> {
70         return applicationContext.getBeanNamesForType(ResourceAssignmentProcessor::class.java)
71             .filter { it.startsWith(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) }
72             .map { it.substringAfter(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) }
73     }
74
75     override suspend fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>,
76                                              artifactTemplate: String,
77                                              resolutionKey: String): String {
78         return resolutionResultService.read(bluePrintRuntimeService, artifactTemplate, resolutionKey)
79     }
80
81     override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
82                                           artifactNames: List<String>,
83                                           properties: Map<String, Any>): MutableMap<String, String> {
84
85         val resolvedParams: MutableMap<String, String> = hashMapOf()
86         artifactNames.forEach { artifactName ->
87             val resolvedContent = resolveResources(bluePrintRuntimeService, nodeTemplateName,
88                 artifactName, properties)
89             resolvedParams[artifactName] = resolvedContent
90         }
91         return resolvedParams
92     }
93
94     override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
95                                           artifactPrefix: String, properties: Map<String, Any>): String {
96
97         // Velocity Artifact Definition Name
98         val artifactTemplate = "$artifactPrefix-template"
99         // Resource Assignment Artifact Definition Name
100         val artifactMapping = "$artifactPrefix-mapping"
101
102         val resolvedContent: String
103         log.info("Resolving resource for template artifact($artifactTemplate) with resource assignment artifact($artifactMapping)")
104
105         val resourceAssignmentContent =
106             bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactMapping)
107
108         val resourceAssignments: MutableList<ResourceAssignment> =
109             JacksonUtils.getListFromJson(resourceAssignmentContent, ResourceAssignment::class.java)
110                     as? MutableList<ResourceAssignment>
111                 ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions")
112
113         // Get the Resource Dictionary Name
114         val resourceDefinitions: MutableMap<String, ResourceDefinition> = ResourceAssignmentUtils
115             .resourceDefinitions(bluePrintRuntimeService.bluePrintContext().rootPath)
116
117         // Resolve resources
118         resolveResourceAssignments(bluePrintRuntimeService,
119             resourceDefinitions,
120             resourceAssignments,
121             artifactPrefix,
122             properties)
123
124         val resolvedParamJsonContent =
125             ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignments.toList())
126
127         resolvedContent = blueprintTemplateService.generateContent(bluePrintRuntimeService, nodeTemplateName,
128             artifactTemplate, resolvedParamJsonContent)
129
130         if (properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT)
131             && properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean) {
132             resolutionResultService.write(properties, resolvedContent, bluePrintRuntimeService, artifactPrefix)
133             log.info("template resolution saved into database successfully : ($properties)")
134         }
135
136         return resolvedContent
137     }
138
139     /**
140      * Iterate the Batch, get the Resource Assignment, dictionary Name, Look for the Resource definition for the
141      * name, then get the type of the Resource Definition, Get the instance for the Resource Type and process the
142      * request.
143      */
144     override suspend fun resolveResourceAssignments(blueprintRuntimeService: BluePrintRuntimeService<*>,
145                                                     resourceDefinitions: MutableMap<String, ResourceDefinition>,
146                                                     resourceAssignments: MutableList<ResourceAssignment>,
147                                                     artifactPrefix: String,
148                                                     properties: Map<String, Any>) {
149
150         val bulkSequenced = BulkResourceSequencingUtils.process(resourceAssignments)
151         val resourceAssignmentRuntimeService =
152             ResourceAssignmentUtils.transformToRARuntimeService(blueprintRuntimeService, artifactPrefix)
153
154         coroutineScope {
155             bulkSequenced.forEach { batchResourceAssignments ->
156                 // Execute Non Dependent Assignments in parallel ( ie asynchronously )
157                 val deferred = batchResourceAssignments.filter { it.name != "*" && it.name != "start" }
158                     .map { resourceAssignment ->
159                         async {
160                             val dictionaryName = resourceAssignment.dictionaryName
161                             val dictionarySource = resourceAssignment.dictionarySource
162                             /**
163                              * Get the Processor name
164                              */
165                             val processorName = processorName(dictionaryName!!, dictionarySource!!, resourceDefinitions)
166
167                             val resourceAssignmentProcessor =
168                                 applicationContext.getBean(processorName) as? ResourceAssignmentProcessor
169                                     ?: throw BluePrintProcessorException("failed to get resource processor ($processorName) " +
170                                             "for resource assignment(${resourceAssignment.name})")
171                             try {
172                                 // Set BluePrint Runtime Service
173                                 resourceAssignmentProcessor.raRuntimeService = resourceAssignmentRuntimeService
174                                 // Set Resource Dictionaries
175                                 resourceAssignmentProcessor.resourceDictionaries = resourceDefinitions
176                                 // Invoke Apply Method
177                                 resourceAssignmentProcessor.applyNB(resourceAssignment)
178
179                                 if (BluePrintConstants.STATUS_FAILURE != resourceAssignment.status
180                                     && properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT)
181                                     && properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean) {
182                                     resourceResolutionDBService.write(properties,
183                                         blueprintRuntimeService,
184                                         artifactPrefix,
185                                         resourceAssignment)
186                                     log.info("Resource resolution saved into database successfully : ($resourceAssignment)")
187                                 }
188
189                                 // Set errors from RA
190                                 blueprintRuntimeService.setBluePrintError(resourceAssignmentRuntimeService.getBluePrintError())
191                             } catch (e: RuntimeException) {
192                                 log.error("Fail in processing ${resourceAssignment.name}", e)
193                                 throw BluePrintProcessorException(e)
194                             }
195                         }
196                     }
197                 log.debug("Resolving (${deferred.size})resources parallel.")
198                 deferred.awaitAll()
199             }
200         }
201
202     }
203
204
205     /**
206      * If the Source instance is "input", then it is not mandatory to have source Resource Definition, So it can
207      *  derive the default input processor.
208      */
209     private fun processorName(dictionaryName: String, dictionarySource: String,
210                               resourceDefinitions: MutableMap<String, ResourceDefinition>): String {
211         val processorName: String = when (dictionarySource) {
212             "input" -> {
213                 "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-input"
214             }
215             "default" -> {
216                 "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-default"
217             }
218             else -> {
219                 val resourceDefinition = resourceDefinitions[dictionaryName]
220                     ?: throw BluePrintProcessorException("couldn't get resource dictionary definition for $dictionaryName")
221
222                 val resourceSource = resourceDefinition.sources[dictionarySource]
223                     ?: throw BluePrintProcessorException("couldn't get resource definition $dictionaryName source($dictionarySource)")
224
225                 ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR.plus(resourceSource.type)
226             }
227         }
228         checkNotEmpty(processorName) {
229             "couldn't get processor name for resource dictionary definition($dictionaryName) source($dictionarySource)"
230         }
231
232         return processorName
233
234     }
235 }