Migrate "ms/controllerblueprints" from ccsdk/apps
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / apps / blueprintsprocessor / functions / resource / resolution / ResourceResolutionService.kt
1 /*
2  *  Copyright © 2017-2018 AT&T Intellectual Property.
3  *  Modifications Copyright © 2018 IBM.
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.apps.blueprintsprocessor.functions.resource.resolution
19
20 import org.onap.ccsdk.apps.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionResultService
21 import org.onap.ccsdk.apps.blueprintsprocessor.functions.resource.resolution.processor.ResourceAssignmentProcessor
22 import org.onap.ccsdk.apps.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
23 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintConstants
24 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintProcessorException
25 import org.onap.ccsdk.apps.controllerblueprints.core.checkNotEmptyOrThrow
26 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintRuntimeService
27 import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintTemplateService
28 import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils
29 import org.onap.ccsdk.apps.controllerblueprints.resource.dict.ResourceAssignment
30 import org.onap.ccsdk.apps.controllerblueprints.resource.dict.ResourceDefinition
31 import org.onap.ccsdk.apps.controllerblueprints.resource.dict.utils.BulkResourceSequencingUtils
32 import org.slf4j.LoggerFactory
33 import org.springframework.context.ApplicationContext
34 import org.springframework.stereotype.Service
35 import java.io.File
36
37 interface ResourceResolutionService {
38
39     fun registeredResourceSources(): List<String>
40
41     fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>, artifactTemplate: String,
42                             resolutionKey: String): String
43
44     fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
45                          artifactNames: List<String>, properties: Map<String, Any>): MutableMap<String, String>
46
47     fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
48                          artifactPrefix: String, properties: Map<String, Any>): String
49
50     fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
51                          artifactMapping: String, artifactTemplate: String?): String
52
53     fun resolveResourceAssignments(blueprintRuntimeService: BluePrintRuntimeService<*>,
54                                    resourceDictionaries: MutableMap<String, ResourceDefinition>,
55                                    resourceAssignments: MutableList<ResourceAssignment>,
56                                    identifierName: String)
57 }
58
59 @Service(ResourceResolutionConstants.SERVICE_RESOURCE_RESOLUTION)
60 open class ResourceResolutionServiceImpl(private var applicationContext: ApplicationContext,
61                                          private var resolutionResultService: ResourceResolutionResultService) :
62         ResourceResolutionService {
63
64     private val log = LoggerFactory.getLogger(ResourceResolutionService::class.java)
65
66     override fun registeredResourceSources(): List<String> {
67         return applicationContext.getBeanNamesForType(ResourceAssignmentProcessor::class.java)
68                 .filter { it.startsWith(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) }
69                 .map { it.substringAfter(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) }
70     }
71
72     override fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
73                                   artifactNames: List<String>,
74                                   properties: Map<String, Any>): MutableMap<String, String> {
75
76         val resolvedParams: MutableMap<String, String> = hashMapOf()
77         artifactNames.forEach { artifactName ->
78             val resolvedContent = resolveResources(bluePrintRuntimeService, nodeTemplateName, artifactName, properties)
79             resolvedParams[artifactName] = resolvedContent
80         }
81         return resolvedParams
82     }
83
84     override fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
85                                   artifactPrefix: String, properties: Map<String, Any>): String {
86
87         // Velocity Artifact Definition Name
88         val artifactTemplate = "$artifactPrefix-template"
89         // Resource Assignment Artifact Definition Name
90         val artifactMapping = "$artifactPrefix-mapping"
91
92         val result = resolveResources(bluePrintRuntimeService, nodeTemplateName, artifactMapping, artifactTemplate)
93
94         if (properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT)
95                 && properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean) {
96             resolutionResultService.write(properties, result, bluePrintRuntimeService, artifactPrefix)
97         }
98
99         return result
100     }
101
102     override fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>, artifactTemplate: String,
103                                      resolutionKey: String): String {
104         return resolutionResultService.read(bluePrintRuntimeService, artifactTemplate, resolutionKey)
105     }
106
107     override fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
108                                   artifactMapping: String, artifactTemplate: String?): String {
109
110         var resolvedContent = ""
111         log.info("Resolving resource for template artifact($artifactTemplate) with resource assignment artifact($artifactMapping)")
112
113         val identifierName = artifactTemplate ?: "no-template"
114
115         val resourceAssignmentContent =
116                 bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactMapping)
117
118         val resourceAssignments: MutableList<ResourceAssignment> =
119                 JacksonUtils.getListFromJson(resourceAssignmentContent, ResourceAssignment::class.java)
120                         as? MutableList<ResourceAssignment>
121                         ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions")
122
123         // Get the Resource Dictionary Name
124         val dictionaryFile = bluePrintRuntimeService.bluePrintContext().rootPath.plus(File.separator)
125                 .plus(BluePrintConstants.TOSCA_DEFINITIONS_DIR).plus(File.separator)
126                 .plus(ResourceResolutionConstants.FILE_NAME_RESOURCE_DEFINITION_TYPES)
127
128         val resourceDictionaries: MutableMap<String, ResourceDefinition> =
129                 JacksonUtils.getMapFromFile(dictionaryFile, ResourceDefinition::class.java)
130                         ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions")
131
132         // Resolve resources
133         resolveResourceAssignments(bluePrintRuntimeService, resourceDictionaries, resourceAssignments, identifierName)
134
135         val resolvedParamJsonContent =
136                 ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignments.toList())
137
138         // Check Template is there
139         if (artifactTemplate != null) {
140             val templateContent =
141                     bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactTemplate)
142             resolvedContent = BluePrintTemplateService.generateContent(templateContent, resolvedParamJsonContent)
143         } else {
144             resolvedContent = resolvedParamJsonContent
145         }
146
147         return resolvedContent
148     }
149
150     /**
151      * Iterate the Batch, get the Resource Assignment, dictionary Name, Look for the Resource definition for the
152      * name, then get the type of the Resource Definition, Get the instance for the Resource Type and process the
153      * request.
154      */
155     override fun resolveResourceAssignments(blueprintRuntimeService: BluePrintRuntimeService<*>,
156                                             resourceDictionaries: MutableMap<String, ResourceDefinition>,
157                                             resourceAssignments: MutableList<ResourceAssignment>,
158                                             identifierName: String) {
159
160         val bulkSequenced = BulkResourceSequencingUtils.process(resourceAssignments)
161         val resourceAssignmentRuntimeService =
162                 ResourceAssignmentUtils.transformToRARuntimeService(blueprintRuntimeService, identifierName)
163
164         bulkSequenced.map { batchResourceAssignments ->
165             batchResourceAssignments.filter { it.name != "*" && it.name != "start" }
166                     .forEach { resourceAssignment ->
167                         val dictionaryName = resourceAssignment.dictionaryName
168                         val dictionarySource = resourceAssignment.dictionarySource
169                         /**
170                          * Get the Processor name
171                          */
172                         val processorName = processorName(dictionaryName!!, dictionarySource!!, resourceDictionaries)
173
174                         val resourceAssignmentProcessor =
175                                 applicationContext.getBean(processorName) as? ResourceAssignmentProcessor
176                                         ?: throw BluePrintProcessorException("failed to get resource processor for name($processorName) " +
177                                                 "for resource assignment(${resourceAssignment.name})")
178                         try {
179                             // Set BluePrint Runtime Service
180                             resourceAssignmentProcessor.raRuntimeService = resourceAssignmentRuntimeService
181                             // Set Resource Dictionaries
182                             resourceAssignmentProcessor.resourceDictionaries = resourceDictionaries
183                             // Invoke Apply Method
184                             resourceAssignmentProcessor.apply(resourceAssignment)
185
186                             // Set errors from RA
187                             blueprintRuntimeService.setBluePrintError(resourceAssignmentRuntimeService.getBluePrintError())
188                         } catch (e: RuntimeException) {
189                             throw BluePrintProcessorException(e)
190                         }
191                     }
192         }
193     }
194
195
196     /**
197      * If the Source instance is "input", then it is not mandatory to have source Resource Definition, So it can
198      *  derive the default input processor.
199      */
200     private fun processorName(dictionaryName: String, dictionarySource: String,
201                               resourceDictionaries: MutableMap<String, ResourceDefinition>): String {
202         var processorName: String? = null
203         when (dictionarySource) {
204             "input" -> {
205                 processorName = "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-input"
206             }
207             "default" -> {
208                 processorName = "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-default"
209             }
210             else -> {
211                 val resourceDefinition = resourceDictionaries[dictionaryName]
212                         ?: throw BluePrintProcessorException("couldn't get resource dictionary definition for $dictionaryName")
213
214                 val resourceSource = resourceDefinition.sources[dictionarySource]
215                         ?: throw BluePrintProcessorException("couldn't get resource definition $dictionaryName source($dictionarySource)")
216
217                 processorName = ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR
218                         .plus(resourceSource.type)
219             }
220         }
221         checkNotEmptyOrThrow(processorName,
222                 "couldn't get processor name for resource dictionary definition($dictionaryName) source" +
223                         "($dictionarySource)")
224
225         return processorName
226
227     }
228 }