2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.sdc.toscaparser.api;
23 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
24 import org.onap.sdc.toscaparser.api.elements.NodeType;
25 import org.onap.sdc.toscaparser.api.elements.PropertyDef;
26 import org.onap.sdc.toscaparser.api.parameters.Input;
27 import org.onap.sdc.toscaparser.api.parameters.Output;
28 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
30 import java.util.ArrayList;
31 import java.util.HashSet;
32 import java.util.LinkedHashMap;
33 import java.util.List;
36 public class SubstitutionMappings {
37 // SubstitutionMappings class declaration
39 // SubstitutionMappings exports the topology template as an
40 // implementation of a Node type.
42 private static final String NODE_TYPE = "node_type";
43 private static final String REQUIREMENTS = "requirements";
44 private static final String CAPABILITIES = "capabilities";
46 private static final String SECTIONS[] = {NODE_TYPE, REQUIREMENTS, CAPABILITIES};
48 private static final String OPTIONAL_OUTPUTS[] = {"tosca_id", "tosca_name", "state"};
50 private LinkedHashMap<String, Object> subMappingDef;
51 private ArrayList<NodeTemplate> nodetemplates;
52 private ArrayList<Input> inputs;
53 private ArrayList<Output> outputs;
54 private ArrayList<Group> groups;
55 private NodeTemplate subMappedNodeTemplate;
56 private LinkedHashMap<String, Object> customDefs;
57 private LinkedHashMap<String, Object> _capabilities;
58 private LinkedHashMap<String, Object> _requirements;
60 public SubstitutionMappings(LinkedHashMap<String, Object> smsubMappingDef,
61 ArrayList<NodeTemplate> smnodetemplates,
62 ArrayList<Input> sminputs,
63 ArrayList<Output> smoutputs,
64 ArrayList<Group> smgroups,
65 NodeTemplate smsubMappedNodeTemplate,
66 LinkedHashMap<String, Object> smcustomDefs) {
68 subMappingDef = smsubMappingDef;
69 nodetemplates = smnodetemplates;
70 inputs = sminputs != null ? sminputs : new ArrayList<Input>();
71 outputs = smoutputs != null ? smoutputs : new ArrayList<Output>();
72 groups = smgroups != null ? smgroups : new ArrayList<Group>();
73 subMappedNodeTemplate = smsubMappedNodeTemplate;
74 customDefs = smcustomDefs != null ? smcustomDefs : new LinkedHashMap<String, Object>();
81 public String getType() {
82 if (subMappingDef != null) {
83 return (String) subMappingDef.get(NODE_TYPE);
88 public ArrayList<NodeTemplate> getNodeTemplates() {
94 def get_node_type(cls, sub_mapping_def):
95 if isinstance(sub_mapping_def, dict):
96 return sub_mapping_def.get(cls.NODE_TYPE)
99 public static String stGetNodeType(LinkedHashMap<String, Object> _subMappingDef) {
100 if (_subMappingDef instanceof LinkedHashMap) {
101 return (String) _subMappingDef.get(NODE_TYPE);
106 public String getNodeType() {
107 return (String) subMappingDef.get(NODE_TYPE);
110 public ArrayList<Input> getInputs() {
114 public ArrayList<Group> getGroups() {
118 public LinkedHashMap<String, Object> getCapabilities() {
119 return (LinkedHashMap<String, Object>) subMappingDef.get(CAPABILITIES);
122 public LinkedHashMap<String, Object> getRequirements() {
123 return (LinkedHashMap<String, Object>) subMappingDef.get(REQUIREMENTS);
126 public NodeType getNodeDefinition() {
127 return new NodeType(getNodeType(), customDefs);
130 private void _validate() {
135 // SubstitutionMapping class syntax validation
137 _validateCapabilities();
138 _validateRequirements();
142 private void _validateKeys() {
143 // validate the keys of substitution mappings
144 for (String key : subMappingDef.keySet()) {
145 boolean bFound = false;
146 for (String s : SECTIONS) {
153 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE232", String.format(
154 "UnknownFieldError: SubstitutionMappings contain unknown field \"%s\"",
160 private void _validateType() {
161 // validate the node_type of substitution mappings
162 String nodeType = (String) subMappingDef.get(NODE_TYPE);
163 if (nodeType == null) {
164 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE233", String.format(
165 "MissingRequiredFieldError: SubstitutionMappings used in topology_template is missing required field \"%s\"",
168 Object nodeTypeDef = customDefs.get(nodeType);
169 if (nodeTypeDef == null) {
170 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE234", String.format(
171 "InvalidNodeTypeError: \"%s\" is invalid", nodeType)));
175 private void _validateInputs() {
176 // validate the inputs of substitution mappings.
178 // The inputs defined by the topology template have to match the
179 // properties of the node type or the substituted node. If there are
180 // more inputs than the substituted node has properties, default values
181 //must be defined for those inputs.
183 HashSet<String> allInputs = new HashSet<>();
184 for (Input inp : inputs) {
185 allInputs.add(inp.getName());
187 HashSet<String> requiredProperties = new HashSet<>();
188 for (PropertyDef pd : getNodeDefinition().getPropertiesDefObjects()) {
189 if (pd.isRequired() && pd.getDefault() == null) {
190 requiredProperties.add(pd.getName());
193 // Must provide inputs for required properties of node type.
194 for (String property : requiredProperties) {
195 // Check property which is 'required' and has no 'default' value
196 if (!allInputs.contains(property)) {
197 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE235", String.format(
198 "MissingRequiredInputError: SubstitutionMappings with node_type \"%s\" is missing required input \"%s\"",
199 getNodeType(), property)));
202 // If the optional properties of node type need to be customized by
203 // substituted node, it also is necessary to define inputs for them,
204 // otherwise they are not mandatory to be defined.
205 HashSet<String> customizedParameters = new HashSet<>();
206 if (subMappedNodeTemplate != null) {
207 customizedParameters.addAll(subMappedNodeTemplate.getProperties().keySet());
209 HashSet<String> allProperties = new HashSet<String>(
210 getNodeDefinition().getPropertiesDef().keySet());
211 HashSet<String> diffset = customizedParameters;
212 diffset.removeAll(allInputs);
213 for (String parameter : diffset) {
214 if (allProperties.contains(parameter)) {
215 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE236", String.format(
216 "MissingRequiredInputError: SubstitutionMappings with node_type \"%s\" is missing required input \"%s\"",
217 getNodeType(), parameter)));
220 // Additional inputs are not in the properties of node type must
221 // provide default values. Currently the scenario may not happen
222 // because of parameters validation in nodetemplate, here is a
224 for (Input inp : inputs) {
226 diffset.removeAll(allProperties);
227 if (diffset.contains(inp.getName()) && inp.getDefault() == null) {
228 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE237", String.format(
229 "MissingRequiredInputError: SubstitutionMappings with node_type \"%s\" is missing rquired input \"%s\"",
230 getNodeType(), inp.getName())));
235 private void _validateCapabilities() {
236 // validate the capabilities of substitution mappings
238 // The capabilities must be in node template which be mapped.
239 LinkedHashMap<String, Object> tplsCapabilities =
240 (LinkedHashMap<String, Object>) subMappingDef.get(CAPABILITIES);
241 List<CapabilityAssignment> nodeCapabilities = null;
242 if (subMappedNodeTemplate != null) {
243 nodeCapabilities = subMappedNodeTemplate.getCapabilities().getAll();
245 if (nodeCapabilities != null) {
246 for (CapabilityAssignment cap : nodeCapabilities) {
247 if (tplsCapabilities != null && tplsCapabilities.get(cap.getName()) == null) {
249 // ValidationIssueCollector.appendException(
250 // UnknownFieldError(what='SubstitutionMappings',
257 private void _validateRequirements() {
258 // validate the requirements of substitution mappings
259 //*****************************************************
260 //TO-DO - Different from Python code!! one is a bug...
261 //*****************************************************
262 // The requirements must be in node template which be mapped.
263 LinkedHashMap<String, Object> tplsRequirements =
264 (LinkedHashMap<String, Object>) subMappingDef.get(REQUIREMENTS);
265 List<RequirementAssignment> nodeRequirements = null;
266 if (subMappedNodeTemplate != null) {
267 nodeRequirements = subMappedNodeTemplate.getRequirements().getAll();
269 if (nodeRequirements != null) {
270 for (RequirementAssignment ro : nodeRequirements) {
271 String cap = ro.getName();
272 if (tplsRequirements != null && tplsRequirements.get(cap) == null) {
274 // ValidationIssueCollector.appendException(
275 // UnknownFieldError(what='SubstitutionMappings',
282 private void _validateOutputs() {
283 // validate the outputs of substitution mappings.
285 // The outputs defined by the topology template have to match the
286 // attributes of the node type or the substituted node template,
287 // and the observable attributes of the substituted node template
288 // have to be defined as attributes of the node type or outputs in
289 // the topology template.
291 // The outputs defined by the topology template have to match the
292 // attributes of the node type according to the specification, but
293 // it's reasonable that there are more inputs than the node type
294 // has properties, the specification will be amended?
296 for (Output output : outputs) {
297 Object ado = getNodeDefinition().getAttributesDef();
298 if (ado != null && ((LinkedHashMap<String, Object>) ado).get(output.getName()) == null) {
299 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE238", String.format(
300 "UnknownOutputError: Unknown output \"%s\" in SubstitutionMappings with node_type \"%s\"",
301 output.getName(), getNodeType())));
307 public String toString() {
308 return "SubstitutionMappings{" +
309 // "subMappingDef=" + subMappingDef +
310 // ", nodetemplates=" + nodetemplates +
311 // ", inputs=" + inputs +
312 // ", outputs=" + outputs +
313 // ", groups=" + groups +
314 ", subMappedNodeTemplate=" + (subMappedNodeTemplate == null ? "" : subMappedNodeTemplate.getName()) +
315 // ", customDefs=" + customDefs +
316 // ", _capabilities=" + _capabilities +
317 // ", _requirements=" + _requirements +
322 public String toLimitedString() {
323 return "SubstitutionMappings{" +
324 "subMappingDef=" + subMappingDef +
325 ", nodetemplates=" + nodetemplates +
326 ", inputs=" + inputs +
327 ", outputs=" + outputs +
328 ", groups=" + groups +
329 ", subMappedNodeTemplate=" + (subMappedNodeTemplate == null ? "" : subMappedNodeTemplate.getName()) +
330 ", customDefs=" + customDefs +
331 ", _capabilities=" + _capabilities +
332 ", _requirements=" + _requirements +
340 from toscaparser.common.exception import ValidationIssueCollector
341 from toscaparser.common.exception import InvalidNodeTypeError
342 from toscaparser.common.exception import MissingDefaultValueError
343 from toscaparser.common.exception import MissingRequiredFieldError
344 from toscaparser.common.exception import MissingRequiredInputError
345 from toscaparser.common.exception import UnknownFieldError
346 from toscaparser.common.exception import UnknownOutputError
347 from toscaparser.elements.nodetype import NodeType
348 from toscaparser.utils.gettextutils import _
350 log = logging.getLogger('tosca')
353 class SubstitutionMappings(object):
354 '''SubstitutionMappings class declaration
356 SubstitutionMappings exports the topology template as an
357 implementation of a Node type.
360 SECTIONS = (NODE_TYPE, REQUIREMENTS, CAPABILITIES) = \
361 ('node_type', 'requirements', 'capabilities')
363 OPTIONAL_OUTPUTS = ['tosca_id', 'tosca_name', 'state']
365 def __init__(self, sub_mapping_def, nodetemplates, inputs, outputs,
366 sub_mapped_node_template, custom_defs):
367 self.nodetemplates = nodetemplates
368 self.sub_mapping_def = sub_mapping_def
369 self.inputs = inputs or []
370 self.outputs = outputs or []
371 self.sub_mapped_node_template = sub_mapped_node_template
372 self.custom_defs = custom_defs or {}
375 self._capabilities = None
376 self._requirements = None
380 if self.sub_mapping_def:
381 return self.sub_mapping_def.get(self.NODE_TYPE)
384 def get_node_type(cls, sub_mapping_def):
385 if isinstance(sub_mapping_def, dict):
386 return sub_mapping_def.get(cls.NODE_TYPE)
390 return self.sub_mapping_def.get(self.NODE_TYPE)
393 def capabilities(self):
394 return self.sub_mapping_def.get(self.CAPABILITIES)
397 def requirements(self):
398 return self.sub_mapping_def.get(self.REQUIREMENTS)
401 def node_definition(self):
402 return NodeType(self.node_type, self.custom_defs)
406 self._validate_keys()
407 self._validate_type()
409 # SubstitutionMapping class syntax validation
410 self._validate_inputs()
411 self._validate_capabilities()
412 self._validate_requirements()
413 self._validate_outputs()
415 def _validate_keys(self):
416 """validate the keys of substitution mappings."""
417 for key in self.sub_mapping_def.keys():
418 if key not in self.SECTIONS:
419 ValidationIssueCollector.appendException(
420 UnknownFieldError(what=_('SubstitutionMappings'),
423 def _validate_type(self):
424 """validate the node_type of substitution mappings."""
425 node_type = self.sub_mapping_def.get(self.NODE_TYPE)
427 ValidationIssueCollector.appendException(
428 MissingRequiredFieldError(
429 what=_('SubstitutionMappings used in topology_template'),
430 required=self.NODE_TYPE))
432 node_type_def = self.custom_defs.get(node_type)
433 if not node_type_def:
434 ValidationIssueCollector.appendException(
435 InvalidNodeTypeError(what=node_type))
437 def _validate_inputs(self):
438 """validate the inputs of substitution mappings.
440 The inputs defined by the topology template have to match the
441 properties of the node type or the substituted node. If there are
442 more inputs than the substituted node has properties, default values
443 must be defined for those inputs.
446 all_inputs = set([input.name for input in self.inputs])
447 required_properties = set([p.name for p in
448 self.node_definition.
449 get_properties_def_objects()
450 if p.required and p.default is None])
451 # Must provide inputs for required properties of node type.
452 for property in required_properties:
453 # Check property which is 'required' and has no 'default' value
454 if property not in all_inputs:
455 ValidationIssueCollector.appendException(
456 MissingRequiredInputError(
457 what=_('SubstitutionMappings with node_type ')
459 input_name=property))
461 # If the optional properties of node type need to be customized by
462 # substituted node, it also is necessary to define inputs for them,
463 # otherwise they are not mandatory to be defined.
464 customized_parameters = set(self.sub_mapped_node_template
465 .get_properties().keys()
466 if self.sub_mapped_node_template else [])
467 all_properties = set(self.node_definition.get_properties_def())
468 for parameter in customized_parameters - all_inputs:
469 if parameter in all_properties:
470 ValidationIssueCollector.appendException(
471 MissingRequiredInputError(
472 what=_('SubstitutionMappings with node_type ')
474 input_name=parameter))
476 # Additional inputs are not in the properties of node type must
477 # provide default values. Currently the scenario may not happen
478 # because of parameters validation in nodetemplate, here is a
480 for input in self.inputs:
481 if input.name in all_inputs - all_properties \
482 and input.default is None:
483 ValidationIssueCollector.appendException(
484 MissingDefaultValueError(
485 what=_('SubstitutionMappings with node_type ')
487 input_name=input.name))
489 def _validate_capabilities(self):
490 """validate the capabilities of substitution mappings."""
492 # The capabilites must be in node template wchich be mapped.
493 tpls_capabilities = self.sub_mapping_def.get(self.CAPABILITIES)
494 node_capabiliteys = self.sub_mapped_node_template.get_capabilities() \
495 if self.sub_mapped_node_template else None
496 for cap in node_capabiliteys.keys() if node_capabiliteys else []:
497 if (tpls_capabilities and
498 cap not in list(tpls_capabilities.keys())):
500 # ValidationIssueCollector.appendException(
501 # UnknownFieldError(what='SubstitutionMappings',
504 def _validate_requirements(self):
505 """validate the requirements of substitution mappings."""
507 # The requirements must be in node template wchich be mapped.
508 tpls_requirements = self.sub_mapping_def.get(self.REQUIREMENTS)
509 node_requirements = self.sub_mapped_node_template.requirements \
510 if self.sub_mapped_node_template else None
511 for req in node_requirements if node_requirements else []:
512 if (tpls_requirements and
513 req not in list(tpls_requirements.keys())):
515 # ValidationIssueCollector.appendException(
516 # UnknownFieldError(what='SubstitutionMappings',
519 def _validate_outputs(self):
520 """validate the outputs of substitution mappings.
522 The outputs defined by the topology template have to match the
523 attributes of the node type or the substituted node template,
524 and the observable attributes of the substituted node template
525 have to be defined as attributes of the node type or outputs in
526 the topology template.
529 # The outputs defined by the topology template have to match the
530 # attributes of the node type according to the specification, but
531 # it's reasonable that there are more inputs than the node type
532 # has properties, the specification will be amended?
533 for output in self.outputs:
534 if output.name not in self.node_definition.get_attributes_def():
535 ValidationIssueCollector.appendException(
537 where=_('SubstitutionMappings with node_type ')
539 output_name=output.name))*/