2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
6 * Copyright (c) 2017-2019 European Software Marketing Ltd.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.aai.babel.parser;
24 import com.google.gson.Gson;
25 import com.google.gson.JsonSyntaxException;
26 import java.io.BufferedReader;
28 import java.io.FileInputStream;
29 import java.io.FileReader;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
35 import java.util.Optional;
36 import java.util.Properties;
37 import java.util.stream.Collectors;
38 import java.util.stream.Stream;
39 import org.onap.aai.babel.logging.LogHelper;
40 import org.onap.aai.babel.xml.generator.XmlArtifactGenerationException;
41 import org.onap.aai.babel.xml.generator.data.GroupConfiguration;
42 import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil;
43 import org.onap.aai.babel.xml.generator.model.Model;
44 import org.onap.aai.babel.xml.generator.model.Resource;
45 import org.onap.aai.babel.xml.generator.model.Widget;
46 import org.onap.aai.babel.xml.generator.model.WidgetType;
47 import org.onap.aai.babel.xml.generator.types.ModelType;
48 import org.onap.aai.cl.api.Logger;
49 import org.onap.sdc.tosca.parser.api.ISdcCsarHelper;
50 import org.onap.sdc.toscaparser.api.Group;
51 import org.onap.sdc.toscaparser.api.NodeTemplate;
52 import org.onap.sdc.toscaparser.api.Property;
53 import org.onap.sdc.toscaparser.api.elements.Metadata;
56 * Wrapper for the sdc-tosca parser.
59 public class ArtifactGeneratorToscaParser {
61 private static Logger log = LogHelper.INSTANCE;
63 public static final String PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE = "artifactgenerator.config";
64 public static final String PROPERTY_TOSCA_MAPPING_FILE = "tosca.mappings.config";
66 public static final String GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND =
67 "Cannot generate artifacts. System property %s not configured";
69 private static final String GENERATOR_AAI_CONFIGFILE_NOT_FOUND =
70 "Cannot generate artifacts. Artifact Generator Configuration file not found at %s";
71 private static final String GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING =
72 "Cannot generate artifacts. Providing Service Metadata is missing for allotted resource %s";
73 private static final String GENERATOR_AAI_PROVIDING_SERVICE_MISSING =
74 "Cannot generate artifacts. Providing Service is missing for allotted resource %s";
76 // Metadata properties
77 private static final String CATEGORY = "category";
78 private static final String ALLOTTED_RESOURCE = "Allotted Resource";
79 private static final String SUBCATEGORY = "subcategory";
80 private static final String TUNNEL_XCONNECT = "Tunnel XConnect";
82 private static final String VERSION = "version";
84 private ISdcCsarHelper csarHelper;
87 * Constructs using csarHelper
92 public ArtifactGeneratorToscaParser(ISdcCsarHelper csarHelper) {
93 this.csarHelper = csarHelper;
97 * Initializes the Widget to UUID mapping configuration.
100 * if an error occurs reading the configuration properties
102 public static void initWidgetConfiguration() throws IOException {
103 log.debug("Getting Widget Configuration");
104 String configLocation = System.getProperty(PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE);
105 if (configLocation != null) {
106 File file = new File(configLocation);
108 Properties properties = new Properties();
109 properties.load(new FileInputStream(file));
110 WidgetConfigurationUtil.setConfig(properties);
112 throw new IllegalArgumentException(String.format(GENERATOR_AAI_CONFIGFILE_NOT_FOUND, configLocation));
115 throw new IllegalArgumentException(
116 String.format(GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND, PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE));
121 * Initializes the group filtering and TOSCA to Widget mapping configuration.
123 * @param configLocation
124 * the pathname to the JSON mappings file
125 * @throws IOException
126 * if the file content could not be read successfully
128 public static void initToscaMappingsConfiguration(String configLocation) throws IOException {
129 log.debug("Getting TOSCA Mappings Configuration");
130 File file = new File(configLocation);
131 if (!file.exists()) {
132 throw new IllegalArgumentException(String.format(GENERATOR_AAI_CONFIGFILE_NOT_FOUND, configLocation));
135 GroupConfiguration config;
137 try (BufferedReader bufferedReader = new BufferedReader(new FileReader(configLocation))) {
138 config = new Gson().fromJson(bufferedReader, GroupConfiguration.class);
139 } catch (JsonSyntaxException e) {
140 throw new IOException("Invalid Mappings Configuration " + configLocation, e);
143 if (config == null) {
144 throw new IOException("There is no content for the Mappings Configuration " + configLocation);
147 WidgetConfigurationUtil.setSupportedInstanceGroups(config.getInstanceGroupTypes());
148 WidgetConfigurationUtil.setWidgetTypes(config.getWidgetTypes());
149 WidgetConfigurationUtil.setWidgetMappings(config.getWidgetMappings());
153 * Process groups for this service node, according to the defined filter.
155 * @param resourceModel
156 * @param serviceNodeTemplate
157 * @return resources for which XML Models should be generated
158 * @throws XmlArtifactGenerationException
159 * if there is no configuration defined for a member Widget of an instance group
161 public List<Resource> processInstanceGroups(Model resourceModel, NodeTemplate serviceNodeTemplate)
162 throws XmlArtifactGenerationException {
163 List<Resource> resources = new ArrayList<>();
164 if (serviceNodeTemplate.getSubMappingToscaTemplate() != null) {
165 List<Group> serviceGroups = csarHelper.getGroupsOfOriginOfNodeTemplate(serviceNodeTemplate);
166 for (Group group : serviceGroups) {
167 if (WidgetConfigurationUtil.isSupportedInstanceGroup(group.getType())) {
168 resources.addAll(processInstanceGroup(resourceModel, group.getMemberNodes(),
169 group.getMetadata().getAllProperties(), group.getProperties()));
177 * Merge a Map of String values with a Map of TOSCA Property Objects to create a combined Map. If there are
178 * duplicate keys then the TOSCA Property value takes precedence.
181 * initial Map of String property values (e.g. from the TOSCA YAML metadata section)
183 * Map of TOSCA Property Type Object values to merge in (or overwrite)
184 * @return a Map of the property values converted to String
186 public Map<String, String> mergeProperties(Map<String, String> stringProps, Map<String, Property> toscaProps) {
187 Map<String, String> props = new HashMap<>(stringProps);
188 toscaProps.forEach((key, toscaProp) -> props.put(key,
189 toscaProp.getValue() == null ? "" : toscaProp.getValue().toString()));
193 public Resource createInstanceGroupModel(Map<String, String> properties) {
194 Resource groupModel = new Resource(WidgetType.valueOf("INSTANCE_GROUP"), true);
195 groupModel.populateModelIdentificationInformation(properties);
200 * Add the resource/widget to the specified model.
204 * resource or widget model to add
205 * @throws XmlArtifactGenerationException
206 * if the relation is a widget and there is no configuration defined for the relation's widget type
208 public void addRelatedModel(final Model model, final Resource relation) throws XmlArtifactGenerationException {
209 if (relation.getModelType() == ModelType.RESOURCE) {
210 model.addResource(relation);
212 model.addWidget(Widget.createWidget(relation.getWidgetType()));
216 public boolean hasAllottedResource(Map<String, String> metadata) {
217 return ALLOTTED_RESOURCE.equals(metadata.get(CATEGORY));
220 public boolean hasSubCategoryTunnelXConnect(Map<String, String> metadata) {
221 return TUNNEL_XCONNECT.equals(metadata.get(SUBCATEGORY));
225 * Process TOSCA Group information for VF Modules.
230 * @throws XmlArtifactGenerationException
231 * if the configured widget mappings do not support the widget type of a VF Module
233 public void processVfModules(List<Resource> resources, Model resourceModel, NodeTemplate serviceNode)
234 throws XmlArtifactGenerationException {
235 // Get the customization UUID for each VF node and use it to get its Groups
236 String uuid = csarHelper.getNodeTemplateCustomizationUuid(serviceNode);
237 List<Group> serviceGroups = csarHelper.getVfModulesByVf(uuid);
239 // Process each VF Group
240 for (Group serviceGroup : serviceGroups) {
241 Model groupModel = Model.getModelFor(serviceGroup.getType());
242 if (groupModel.hasWidgetType("VFMODULE")) {
243 processVfModule(resources, resourceModel, serviceGroup, serviceNode, (Resource) groupModel);
249 * @param resourceModel
250 * @param resourceNodeTemplates
252 public void processResourceModels(Model resourceModel, List<NodeTemplate> resourceNodeTemplates) {
253 boolean foundProvidingService = false;
255 for (NodeTemplate resourceNodeTemplate : resourceNodeTemplates) {
256 String nodeTypeName = resourceNodeTemplate.getType();
257 Metadata metadata = resourceNodeTemplate.getMetaData();
258 String metaDataType = Optional.ofNullable(metadata).map(m -> m.getValue("type")).orElse(nodeTypeName);
259 Resource model = Model.getModelFor(nodeTypeName, metaDataType);
261 if (metadata != null && hasAllottedResource(metadata.getAllProperties())
262 && model.hasWidgetType("VSERVER")) {
263 model = new Resource(WidgetType.valueOf("ALLOTTED_RESOURCE"), false);
264 Map<String, Object> props = new HashMap<>();
265 props.put("providingService", true);
266 model.setProperties(props);
269 foundProvidingService |= processModel(resourceModel, metadata, model, resourceNodeTemplate.getProperties());
272 if (resourceModel.hasWidgetType("ALLOTTED_RESOURCE") && !foundProvidingService) {
273 final String modelInvariantId = resourceModel.getModelId();
274 throw new IllegalArgumentException(String.format(GENERATOR_AAI_PROVIDING_SERVICE_MISSING,
275 modelInvariantId == null ? "<null ID>" : modelInvariantId));
280 * Create an Instance Group Model and populate it with the supplied data.
282 * @param resourceModel
283 * the Resource node template Model
285 * the Resources and Widgets belonging to the Group
286 * @param metaProperties
287 * the metadata of the Group
289 * the properties of the Group
290 * @return the Instance Group and Member resource models
291 * @throws XmlArtifactGenerationException
292 * if there is no configuration defined for one of the member Widgets
294 private List<Resource> processInstanceGroup(Model resourceModel, ArrayList<NodeTemplate> memberNodes,
295 Map<String, String> metaProperties, Map<String, Property> properties)
296 throws XmlArtifactGenerationException {
297 Resource groupModel = createInstanceGroupModel(mergeProperties(metaProperties, properties));
298 resourceModel.addResource(groupModel);
299 List<Resource> resources = Stream.of(groupModel).collect(Collectors.toList());
301 if (memberNodes != null && !memberNodes.isEmpty()) {
302 resources.addAll(generateResourcesAndWidgets(memberNodes, groupModel));
311 * @return a list of Resources
312 * @throws XmlArtifactGenerationException
313 * if a member node template is a widget and there is no configuration defined for that relation's
316 private List<Resource> generateResourcesAndWidgets(final ArrayList<NodeTemplate> memberNodes,
317 final Resource groupModel) throws XmlArtifactGenerationException {
318 log.debug(String.format("Processing member nodes for Group %s (invariant UUID %s)", //
319 groupModel.getModelName(), groupModel.getModelId()));
321 List<Resource> resources = new ArrayList<>();
323 for (NodeTemplate nodeTemplate : memberNodes) {
324 String nodeTypeName = nodeTemplate.getType();
325 final String metadataType = nodeTemplate.getMetaData().getValue("type");
327 log.debug(String.format("Get model for %s (metadata type %s)", nodeTypeName, metadataType));
328 Resource memberModel = Model.getModelFor(nodeTypeName, metadataType);
330 if (memberModel != null) {
331 memberModel.populateModelIdentificationInformation(nodeTemplate.getMetaData().getAllProperties());
333 log.debug(String.format("Generating grouped %s (%s) from TOSCA type %s",
334 memberModel.getClass().getSuperclass().getSimpleName(), memberModel.getClass(), nodeTypeName));
336 addRelatedModel(groupModel, memberModel);
337 if (memberModel.getModelType() == ModelType.RESOURCE) {
338 resources.add(memberModel);
348 * @param groupDefinition
351 * @throws XmlArtifactGenerationException
352 * if the configured widget mappings do not support the widget type of a VF Module
354 private void processVfModule(List<Resource> resources, Model vfModel, Group groupDefinition,
355 NodeTemplate serviceNode, Resource groupModel) throws XmlArtifactGenerationException {
356 groupModel.populateModelIdentificationInformation(
357 mergeProperties(groupDefinition.getMetadata().getAllProperties(), groupDefinition.getProperties()));
359 processVfModuleGroup(groupModel, csarHelper.getMembersOfVfModule(serviceNode, groupDefinition));
361 vfModel.addResource(groupModel); // Add group (VfModule) to the (VF) model
362 // Check if we have already encountered the same VfModule across all the artifacts
363 if (!resources.contains(groupModel)) {
364 resources.add(groupModel);
371 * @throws XmlArtifactGenerationException
372 * if the configured widget mappings do not support the widget type of a member
374 private void processVfModuleGroup(Resource groupModel, List<NodeTemplate> members)
375 throws XmlArtifactGenerationException {
376 if (members != null && !members.isEmpty()) {
377 // Get names of the members of the service group
378 List<String> memberNames = members.stream().map(NodeTemplate::getName).collect(Collectors.toList());
379 groupModel.setMembers(memberNames);
380 for (NodeTemplate member : members) {
381 processGroupMembers(groupModel, member);
387 * Process the Widget members of a VF Module Group
390 * the group resource model
392 * the group member to process
393 * @throws XmlArtifactGenerationException
394 * if the configured widget mappings do not support the widget type of the member
396 private void processGroupMembers(Resource group, NodeTemplate member) throws XmlArtifactGenerationException {
397 Resource resource = Model.getModelFor(member.getType());
399 log.debug(member.getType() + " mapped to " + resource);
401 if (resource.hasWidgetType("L3_NET")) {
402 // An l3-network inside a vf-module is treated as a Widget
403 resource.setModelType(ModelType.WIDGET);
406 if (resource.getModelType() == ModelType.WIDGET) {
407 Widget widget = Widget.createWidget(resource.getWidgetType());
408 widget.addKey(member.getName());
409 // Add the widget element encountered to the Group model
410 group.addWidget(widget);
415 * Create a Map of property name against String property value from the input Map
419 * @return Map of property name against String property value
421 private Map<String, String> populateStringProperties(Map<String, Property> inputMap) {
422 return inputMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
423 e -> e.getValue().getValue() == null ? "" : e.getValue().getValue().toString()));
427 * If the specified resourceNode is a type of Resource, add it to the specified resourceModel. If the Resource type
428 * is ProvidingService then return true, otherwise return false.
430 * @param resourceModel
433 * for populating the Resource IDs
434 * @param resourceNode
435 * any Model (will be ignored if not a Resource)
436 * @param nodeProperties
437 * the node properties
438 * @return whether or not a ProvidingService was processed
440 private boolean processModel(Model resourceModel, Metadata metaData, Resource resourceNode,
441 Map<String, Property> nodeProperties) {
442 boolean foundProvidingService = resourceNode != null
443 && (boolean) Optional.ofNullable(resourceNode.getProperties().get("providingService")).orElse(false);
445 if (foundProvidingService) {
446 processProvidingService(resourceModel, resourceNode, nodeProperties);
447 } else if (resourceNode != null && resourceNode.getModelType() == ModelType.RESOURCE
448 && !resourceNode.hasWidgetType("L3_NET")) {
449 if (metaData != null) {
450 resourceNode.populateModelIdentificationInformation(metaData.getAllProperties());
452 resourceModel.addResource(resourceNode);
454 return foundProvidingService;
457 private void processProvidingService(Model resourceModel, Resource resourceNode,
458 Map<String, Property> nodeProperties) {
459 if (nodeProperties == null || nodeProperties.get("providing_service_uuid") == null
460 || nodeProperties.get("providing_service_invariant_uuid") == null) {
461 throw new IllegalArgumentException(
462 String.format(GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING, resourceModel.getModelId()));
464 Map<String, String> properties = populateStringProperties(nodeProperties);
465 properties.put(VERSION, "1.0");
466 resourceNode.populateModelIdentificationInformation(properties);
467 resourceModel.addResource(resourceNode);