2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2019 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 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=========================================================
21 package org.onap.aai.babel.parser;
23 import com.google.gson.Gson;
24 import java.io.BufferedReader;
26 import java.io.FileInputStream;
27 import java.io.FileNotFoundException;
28 import java.io.FileReader;
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.List;
34 import java.util.Optional;
35 import java.util.Properties;
36 import java.util.stream.Collectors;
37 import java.util.stream.Stream;
38 import org.onap.aai.babel.logging.LogHelper;
39 import org.onap.aai.babel.xml.generator.data.GroupConfiguration;
40 import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil;
41 import org.onap.aai.babel.xml.generator.model.AllotedResource;
42 import org.onap.aai.babel.xml.generator.model.InstanceGroup;
43 import org.onap.aai.babel.xml.generator.model.L3NetworkWidget;
44 import org.onap.aai.babel.xml.generator.model.Model;
45 import org.onap.aai.babel.xml.generator.model.ProvidingService;
46 import org.onap.aai.babel.xml.generator.model.Resource;
47 import org.onap.aai.babel.xml.generator.model.VfModule;
48 import org.onap.aai.babel.xml.generator.model.Widget;
49 import org.onap.aai.cl.api.Logger;
50 import org.onap.sdc.tosca.parser.api.ISdcCsarHelper;
51 import org.onap.sdc.toscaparser.api.Group;
52 import org.onap.sdc.toscaparser.api.NodeTemplate;
53 import org.onap.sdc.toscaparser.api.Property;
54 import org.onap.sdc.toscaparser.api.elements.Metadata;
57 * Wrapper for the sdc-tosca parser
60 public class ArtifactGeneratorToscaParser {
62 private static Logger log = LogHelper.INSTANCE;
64 public static final String PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE = "artifactgenerator.config";
65 public static final String PROPERTY_GROUP_FILTERS_CONFIG_FILE = "groupfilter.config";
67 private static final String GENERATOR_AAI_CONFIGFILE_NOT_FOUND =
68 "Cannot generate artifacts. Artifact Generator Configuration file not found at %s";
69 private static final String GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND =
70 "Cannot generate artifacts. System property %s not configured";
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 * Get or create the artifact description.
101 * @return the artifact model's description
103 public static String getArtifactDescription(Model model) {
104 switch (model.getModelType()) {
106 return "AAI Service Model";
108 return "AAI Resource Model";
110 return model.getModelDescription();
115 * Initialises the widget configuration.
117 * @throws IOException
119 public static void initWidgetConfiguration() throws IOException {
120 log.debug("Getting Widget Configuration");
121 String configLocation = System.getProperty(PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE);
122 if (configLocation != null) {
123 File file = new File(configLocation);
125 Properties properties = new Properties();
126 properties.load(new FileInputStream(file));
127 WidgetConfigurationUtil.setConfig(properties);
129 throw new IllegalArgumentException(String.format(GENERATOR_AAI_CONFIGFILE_NOT_FOUND, configLocation));
132 throw new IllegalArgumentException(
133 String.format(GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND, PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE));
138 * Initialises the group filtering and mapping configuration.
140 * @throws FileNotFoundException
143 public static void initGroupFilterConfiguration() throws FileNotFoundException {
144 log.debug("Getting Filter Types Configuration");
145 String configLocation = System.getProperty(PROPERTY_GROUP_FILTERS_CONFIG_FILE);
146 if (configLocation == null) {
147 throw new IllegalArgumentException(
148 String.format(GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND, PROPERTY_GROUP_FILTERS_CONFIG_FILE));
151 File file = new File(configLocation);
152 if (!file.exists()) {
153 throw new IllegalArgumentException(String.format(GENERATOR_AAI_CONFIGFILE_NOT_FOUND, configLocation));
156 BufferedReader bufferedReader = new BufferedReader(new FileReader(configLocation));
157 GroupConfiguration config = new Gson().fromJson(bufferedReader, GroupConfiguration.class);
158 WidgetConfigurationUtil.setSupportedInstanceGroups(config.getInstanceGroupTypes());
159 WidgetConfigurationUtil.setTypeMappings(config.getToscaToWidgetMappings());
163 * Process groups for this service node, according to the defined filter.
165 * @param resourceModel
166 * @param serviceNodeTemplate
167 * @return resources for which XML Models should be generated
169 public List<Resource> processInstanceGroups(Model resourceModel, NodeTemplate serviceNodeTemplate) {
170 List<Resource> resources = new ArrayList<>();
171 if (serviceNodeTemplate.getSubMappingToscaTemplate() != null) {
172 List<Group> serviceGroups = csarHelper.getGroupsOfOriginOfNodeTemplate(serviceNodeTemplate);
173 for (Group group : serviceGroups) {
174 if (WidgetConfigurationUtil.isSupportedInstanceGroup(group.getType())) {
175 resources.addAll(processInstanceGroup(resourceModel, group.getMemberNodes(),
176 group.getMetadata().getAllProperties(), group.getProperties()));
184 * Merge a Map of String values with a Map of TOSCA Property Objects to create a combined Map. If there are
185 * duplicate keys then the TOSCA Property value takes precedence.
188 * initial Map of String property values (e.g. from the TOSCA YAML metadata section)
190 * Map of TOSCA Property Type Object values to merge in (or overwrite)
191 * @return a Map of the property values converted to String
193 public Map<String, String> mergeProperties(Map<String, String> stringProps, Map<String, Property> toscaProps) {
194 Map<String, String> props = new HashMap<>(stringProps);
195 toscaProps.forEach((key, toscaProp) -> props.put(key,
196 toscaProp.getValue() == null ? "" : toscaProp.getValue().toString()));
200 public Resource createInstanceGroupModel(Map<String, String> properties) {
201 Resource groupModel = new InstanceGroup();
202 groupModel.populateModelIdentificationInformation(properties);
210 public void addRelatedModel(final Model model, final Model relation) {
211 if (relation instanceof Resource) {
212 model.addResource((Resource) relation);
214 model.addWidget((Widget) relation);
218 public String normaliseNodeTypeName(NodeTemplate nodeType) {
219 String nodeTypeName = nodeType.getType();
220 Metadata metadata = nodeType.getMetaData();
221 if (metadata != null && hasAllottedResource(metadata.getAllProperties())) {
222 if (nodeType.getType().contains("org.openecomp.resource.vf.")) {
223 nodeTypeName = "org.openecomp.resource.vf.allottedResource";
225 if (nodeType.getType().contains("org.openecomp.resource.vfc.")) {
226 nodeTypeName = "org.openecomp.resource.vfc.AllottedResource";
232 public boolean hasAllottedResource(Map<String, String> metadata) {
233 return ALLOTTED_RESOURCE.equals(metadata.get(CATEGORY));
236 public boolean hasSubCategoryTunnelXConnect(Map<String, String> metadata) {
237 return TUNNEL_XCONNECT.equals(metadata.get(SUBCATEGORY));
241 * Process TOSCA Group information for VF Modules.
247 public void processVfModules(List<Resource> resources, Model resourceModel, NodeTemplate serviceNode) {
248 // Get the customisation UUID for each VF node and use it to get its Groups
249 String uuid = csarHelper.getNodeTemplateCustomizationUuid(serviceNode);
250 List<Group> serviceGroups = csarHelper.getVfModulesByVf(uuid);
252 // Process each VF Group
253 for (Group serviceGroup : serviceGroups) {
254 Model groupModel = Model.getModelFor(serviceGroup.getType());
255 if (groupModel instanceof VfModule) {
256 processVfModule(resources, resourceModel, serviceGroup, serviceNode, (VfModule) groupModel);
262 * @param resourceModel
263 * @param resourceNodeTemplates
265 public void processResourceModels(Model resourceModel, List<NodeTemplate> resourceNodeTemplates) {
266 boolean foundProvidingService = false;
268 for (NodeTemplate resourceNodeTemplate : resourceNodeTemplates) {
269 String nodeTypeName = normaliseNodeTypeName(resourceNodeTemplate);
270 Metadata metaData = resourceNodeTemplate.getMetaData();
271 String metaDataType = Optional.ofNullable(metaData).map(m -> m.getValue("type")).orElse(nodeTypeName);
272 Model resourceNode = Model.getModelFor(nodeTypeName, metaDataType);
273 foundProvidingService |=
274 processModel(resourceModel, metaData, resourceNode, resourceNodeTemplate.getProperties());
277 if (resourceModel instanceof AllotedResource && !foundProvidingService) {
278 final String modelInvariantId = resourceModel.getModelId();
279 throw new IllegalArgumentException(String.format(GENERATOR_AAI_PROVIDING_SERVICE_MISSING,
280 modelInvariantId == null ? "<null ID>" : modelInvariantId));
285 * Create an Instance Group Model and populate it with the supplied data.
287 * @param resourceModel
288 * the Resource node template Model
290 * the Resources and Widgets belonging to the Group
291 * @param metaProperties
292 * the metadata of the Group
294 * the properties of the Group
295 * @return the Instance Group and Member resource models
297 private List<Resource> processInstanceGroup(Model resourceModel, ArrayList<NodeTemplate> memberNodes,
298 Map<String, String> metaProperties, Map<String, Property> properties) {
299 Resource groupModel = createInstanceGroupModel(mergeProperties(metaProperties, properties));
300 resourceModel.addResource(groupModel);
301 List<Resource> resources = Stream.of(groupModel).collect(Collectors.toList());
303 if (memberNodes != null && !memberNodes.isEmpty()) {
304 resources.addAll(generateResourcesAndWidgets(memberNodes, groupModel));
315 private List<Resource> generateResourcesAndWidgets(final ArrayList<NodeTemplate> memberNodes,
316 final Resource groupModel) {
317 log.debug(String.format("Processing member nodes for Group %s (invariant UUID %s)", //
318 groupModel.getModelName(), groupModel.getModelId()));
320 List<Resource> resources = new ArrayList<>();
322 for (NodeTemplate nodeTemplate : memberNodes) {
323 String nodeTypeName = normaliseNodeTypeName(nodeTemplate);
324 final String metadataType = nodeTemplate.getMetaData().getValue("type");
326 log.debug(String.format("Get model for %s (metadata type %s)", nodeTypeName, metadataType));
327 Model memberModel = Model.getModelFor(nodeTypeName, metadataType);
329 if (memberModel != null) {
330 memberModel.populateModelIdentificationInformation(nodeTemplate.getMetaData().getAllProperties());
332 log.debug(String.format("Generating grouped %s (%s) from TOSCA type %s",
333 memberModel.getClass().getSuperclass().getSimpleName(), memberModel.getClass(), nodeTypeName));
335 addRelatedModel(groupModel, memberModel);
336 if (memberModel instanceof Resource) {
337 resources.add((Resource) memberModel);
344 private void processVfModule(List<Resource> resources, Model vfModel, Group groupDefinition,
345 NodeTemplate serviceNode, VfModule groupModel) {
346 groupModel.populateModelIdentificationInformation(
347 mergeProperties(groupDefinition.getMetadata().getAllProperties(), groupDefinition.getProperties()));
349 processVfModuleGroup(groupModel, csarHelper.getMembersOfVfModule(serviceNode, groupDefinition));
351 vfModel.addResource(groupModel); // Add group (VfModule) to the (VF) model
352 // Check if we have already encountered the same VfModule across all the artifacts
353 if (!resources.contains(groupModel)) {
354 resources.add(groupModel);
358 private void processVfModuleGroup(VfModule groupModel, List<NodeTemplate> members) {
359 if (members != null && !members.isEmpty()) {
360 // Get names of the members of the service group
361 List<String> memberNames = members.stream().map(NodeTemplate::getName).collect(Collectors.toList());
362 groupModel.setMembers(memberNames);
363 for (NodeTemplate member : members) {
364 processGroupMembers(groupModel, member);
369 private void processGroupMembers(Model group, NodeTemplate member) {
371 // L3-network inside vf-module to be generated as Widget a special handling.
372 if (member.getType().contains("org.openecomp.resource.vl")) {
373 resourceNode = new L3NetworkWidget();
375 resourceNode = Model.getModelFor(member.getType());
377 if (resourceNode != null && !(resourceNode instanceof Resource)) {
378 Widget widget = (Widget) resourceNode;
379 widget.addKey(member.getName());
380 // Add the widget element encountered to the Group model
381 group.addWidget(widget);
386 * Create a Map of property name against String property value from the input Map
390 * @return Map of property name against String property value
392 private Map<String, String> populateStringProperties(Map<String, Property> inputMap) {
393 return inputMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
394 e -> e.getValue().getValue() == null ? "" : e.getValue().getValue().toString()));
398 * If the specified resourceNode is a type of Resource, add it to the specified resourceModel. If the Resource type
399 * is ProvidingService return true, otherwise return false.
401 * @param resourceModel
404 * for populating the Resource IDs
405 * @param resourceNode
406 * any Model (will be ignored if not a Resource)
407 * @param nodeProperties
408 * the node properties
409 * @return whether or not a ProvidingService was prcoessed
411 private boolean processModel(Model resourceModel, Metadata metaData, Model resourceNode,
412 Map<String, Property> nodeProperties) {
413 boolean foundProvidingService = false;
414 if (resourceNode instanceof ProvidingService) {
415 foundProvidingService = true;
416 processProvidingService(resourceModel, resourceNode, nodeProperties);
417 } else if (resourceNode instanceof Resource && !(resourceNode.getWidgetType().equals(Widget.Type.L3_NET))) {
418 if (metaData != null) {
419 resourceNode.populateModelIdentificationInformation(metaData.getAllProperties());
421 resourceModel.addResource((Resource) resourceNode);
423 return foundProvidingService;
426 private void processProvidingService(Model resourceModel, Model resourceNode,
427 Map<String, Property> nodeProperties) {
428 if (nodeProperties == null || nodeProperties.get("providing_service_uuid") == null
429 || nodeProperties.get("providing_service_invariant_uuid") == null) {
430 throw new IllegalArgumentException(
431 String.format(GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING, resourceModel.getModelId()));
433 Map<String, String> properties = populateStringProperties(nodeProperties);
434 properties.put(VERSION, "1.0");
435 resourceNode.populateModelIdentificationInformation(properties);
436 resourceModel.addResource((Resource) resourceNode);