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.functions;
23 import org.onap.sdc.toscaparser.api.CapabilityAssignment;
24 import org.onap.sdc.toscaparser.api.NodeTemplate;
25 import org.onap.sdc.toscaparser.api.Property;
26 import org.onap.sdc.toscaparser.api.RelationshipTemplate;
27 import org.onap.sdc.toscaparser.api.RequirementAssignment;
28 import org.onap.sdc.toscaparser.api.TopologyTemplate;
29 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
30 import org.onap.sdc.toscaparser.api.elements.CapabilityTypeDef;
31 import org.onap.sdc.toscaparser.api.elements.EntityType;
32 import org.onap.sdc.toscaparser.api.elements.NodeType;
33 import org.onap.sdc.toscaparser.api.elements.PropertyDef;
34 import org.onap.sdc.toscaparser.api.elements.RelationshipType;
35 import org.onap.sdc.toscaparser.api.elements.StatefulEntityType;
36 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
38 import java.util.ArrayList;
39 import java.util.LinkedHashMap;
41 public class GetProperty extends Function {
42 // Get a property value of an entity defined in the same service template
46 // * Node template name | SELF | HOST | SOURCE | TARGET.
47 // * Requirement or capability name (optional).
50 // If requirement or capability name is specified, the behavior is as follows:
51 // The req or cap name is first looked up in the specified node template's
53 // If found, it would search for a matching capability
54 // of an other node template and get its property as specified in function
56 // Otherwise, the req or cap name would be looked up in the specified
57 // node template's capabilities and if found, it would return the property of
58 // the capability as specified in function arguments.
62 // * { get_property: [ mysql_server, port ] }
63 // * { get_property: [ SELF, db_port ] }
64 // * { get_property: [ SELF, database_endpoint, port ] }
65 // * { get_property: [ SELF, database_endpoint, port, 1 ] }
68 public GetProperty(TopologyTemplate ttpl, Object context, String name, ArrayList<Object> args) {
69 super(ttpl, context, name, args);
74 if (args.size() < 2) {
75 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE167",
76 "ValueError: Illegal arguments for function \"get_property\". Expected arguments: \"node-template-name\", \"req-or-cap\" (optional), \"property name.\""));
79 if (args.size() == 2) {
80 Property foundProp = _findProperty((String) args.get(1));
81 if (foundProp == null) {
84 Object prop = foundProp.getValue();
85 if (prop instanceof Function) {
86 getFunction(toscaTpl, context, prop, toscaTpl.getResolveGetInput());
88 } else if (args.size() >= 3) {
89 // do not use _find_property to avoid raise KeyError
90 // if the prop is not found
91 // First check if there is property with this name
92 NodeTemplate nodeTpl = _findNodeTemplate((String) args.get(0));
93 LinkedHashMap<String, Property> props;
94 if (nodeTpl != null) {
95 props = nodeTpl.getProperties();
97 props = new LinkedHashMap<>();
100 Object propertyValue;
101 if (props.get(args.get(1)) != null) {
102 propertyValue = ((Property) props.get(args.get(1))).getValue();
105 // then check the req or caps
106 propertyValue = _findReqOrCapProperty((String) args.get(1), (String) args.get(2));
109 if (args.size() > index) {
110 for (Object elem : args.subList(index, args.size() - 1)) {
111 if (propertyValue instanceof ArrayList) {
112 int intElem = (int) elem;
113 propertyValue = _getIndexValue(propertyValue, intElem);
115 propertyValue = _getAttributeValue(propertyValue, (String) elem);
122 @SuppressWarnings("unchecked")
123 private Object _findReqOrCapProperty(String reqOrCap, String propertyName) {
124 NodeTemplate nodeTpl = _findNodeTemplate((String) args.get(0));
125 if (nodeTpl == null) {
128 // look for property in node template's requirements
129 for (RequirementAssignment req : nodeTpl.getRequirements().getAll()) {
130 String nodeName = req.getNodeTemplateName();
131 if (req.getName().equals(reqOrCap)) {
132 NodeTemplate nodeTemplate = _findNodeTemplate(nodeName);
133 return _getCapabilityProperty(nodeTemplate, req.getName(), propertyName, true);
136 // If requirement was not found, look in node template's capabilities
137 return _getCapabilityProperty(nodeTpl, reqOrCap, propertyName, true);
140 private Object _getCapabilityProperty(NodeTemplate nodeTemplate,
141 String capabilityName,
143 boolean throwErrors) {
145 // Gets a node template capability property
146 Object property = null;
147 CapabilityAssignment cap = nodeTemplate.getCapabilities().getCapabilityByName(capabilityName);
149 LinkedHashMap<String, Property> props = cap.getProperties();
150 if (props != null && props.get(propertyName) != null) {
151 property = ((Property) props.get(propertyName)).getValue();
153 if (property == null && throwErrors) {
154 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE168", String.format(
155 "KeyError: Property \"%s\" was not found in capability \"%s\" of node template \"%s\" referenced from node template \"%s\"",
156 propertyName, capabilityName, nodeTemplate.getName(), ((NodeTemplate) context).getName())));
161 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE169", String.format(
162 "KeyError: Requirement/CapabilityAssignment \"%s\" referenced from node template \"%s\" was not found in node template \"%s\"",
163 capabilityName, ((NodeTemplate) context).getName(), nodeTemplate.getName())));
169 private Property _findProperty(String propertyName) {
170 NodeTemplate nodeTpl = _findNodeTemplate((String) args.get(0));
171 if (nodeTpl == null) {
174 LinkedHashMap<String, Property> props = nodeTpl.getProperties();
175 Property found = props.get(propertyName);
177 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE170", String.format(
178 "KeyError: Property \"%s\" was not found in node template \"%s\"",
179 propertyName, nodeTpl.getName())));
184 private NodeTemplate _findNodeTemplate(String nodeTemplateName) {
185 if (nodeTemplateName.equals(SELF)) {
186 return (NodeTemplate) context;
188 // enable the HOST value in the function
189 if (nodeTemplateName.equals(HOST)) {
190 NodeTemplate node = _findHostContainingProperty(null);
192 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE171", String.format(
193 "KeyError: Property \"%s\" was not found in capability \"%s\" of node template \"%s\" referenced from node template \"%s\"",
194 (String) args.get(2), (String) args.get(1), ((NodeTemplate) context).getName())));
199 if (nodeTemplateName.equals(TARGET)) {
200 if (!(((RelationshipTemplate) context).getTypeDefinition() instanceof RelationshipType)) {
201 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE172",
202 "KeyError: \"TARGET\" keyword can only be used in context to \"Relationships\" target node"));
205 return ((RelationshipTemplate) context).getTarget();
207 if (nodeTemplateName.equals(SOURCE)) {
208 if (!(((RelationshipTemplate) context).getTypeDefinition() instanceof RelationshipType)) {
209 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE173",
210 "KeyError: \"SOURCE\" keyword can only be used in context to \"Relationships\" target node"));
213 return ((RelationshipTemplate) context).getSource();
215 if (toscaTpl.getNodeTemplates() == null) {
218 for (NodeTemplate nodeTemplate : toscaTpl.getNodeTemplates()) {
219 if (nodeTemplate.getName().equals(nodeTemplateName)) {
223 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE174", String.format(
224 "KeyError: Node template \"%s\" was not found. Referenced from Node Template \"%s\"",
225 nodeTemplateName, ((NodeTemplate) context).getName())));
230 @SuppressWarnings("rawtypes")
231 private Object _getIndexValue(Object value, int index) {
232 if (value instanceof ArrayList) {
233 if (index < ((ArrayList) value).size()) {
234 return ((ArrayList) value).get(index);
236 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE175", String.format(
237 "KeyError: Property \"%s\" found in capability \"%s\" referenced from node template \"%s\" must have an element with index %d",
238 args.get(2), args.get(1), ((NodeTemplate) context).getName(), index)));
242 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE176", String.format(
243 "KeyError: Property \"%s\" found in capability \"%s\" referenced from node template \"%s\" must be a list",
244 args.get(2), args.get(1), ((NodeTemplate) context).getName())));
249 @SuppressWarnings("unchecked")
250 private Object _getAttributeValue(Object value, String attribute) {
251 if (value instanceof LinkedHashMap) {
252 Object ov = ((LinkedHashMap<String, Object>) value).get(attribute);
256 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE177", String.format(
257 "KeyError: Property \"%s\" found in capability \"%s\" referenced from node template \"%s\" must have an attribute named \"%s\"",
258 args.get(2), args.get(1), ((NodeTemplate) context).getName(), attribute)));
261 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE178", String.format(
262 "KeyError: Property \"%s\" found in capability \"%s\" referenced from node template \"%s\" must be a dict",
263 args.get(2), args.get(1), ((NodeTemplate) context).getName())));
268 // Add this functions similar to get_attribute case
269 private NodeTemplate _findHostContainingProperty(String nodeTemplateName) {
270 if (nodeTemplateName == null) {
271 nodeTemplateName = SELF;
273 NodeTemplate nodeTemplate = _findNodeTemplate(nodeTemplateName);
274 LinkedHashMap<String, Object> hostedOnRel = (LinkedHashMap<String, Object>)
275 EntityType.TOSCA_DEF.get(HOSTED_ON);
276 for (RequirementAssignment requirement : nodeTemplate.getRequirements().getAll()) {
277 String targetName = requirement.getNodeTemplateName();
278 NodeTemplate targetNode = _findNodeTemplate(targetName);
279 NodeType targetType = (NodeType) targetNode.getTypeDefinition();
280 for (CapabilityTypeDef capDef : targetType.getCapabilitiesObjects()) {
281 if (capDef.inheritsFrom((ArrayList<String>) hostedOnRel.get("valid_target_types"))) {
282 if (_propertyExistsInType(targetType)) {
285 // If requirement was not found, look in node
286 // template's capabilities
287 if (args.size() > 2 &&
288 _getCapabilityProperty(targetNode, (String) args.get(1), (String) args.get(2), false) != null) {
292 return _findHostContainingProperty(targetName);
300 private boolean _propertyExistsInType(StatefulEntityType typeDefinition) {
301 LinkedHashMap<String, PropertyDef> propsDef = typeDefinition.getPropertiesDef();
302 return propsDef.keySet().contains((String) args.get(1));
306 public Object result() {
307 Object propertyValue;
308 if (args.size() >= 3) {
309 // First check if there is property with this name
310 NodeTemplate nodeTpl = _findNodeTemplate((String) args.get(0));
311 LinkedHashMap<String, Property> props;
312 if (nodeTpl != null) {
313 props = nodeTpl.getProperties();
315 props = new LinkedHashMap<>();
318 if (props.get(args.get(1)) != null) {
319 propertyValue = ((Property) props.get(args.get(1))).getValue();
322 // then check the req or caps
323 propertyValue = _findReqOrCapProperty((String) args.get(1), (String) args.get(2));
326 if (args.size() > index) {
327 for (Object elem : args.subList(index, args.size() - 1)) {
328 if (propertyValue instanceof ArrayList) {
329 int intElem = (int) elem;
330 propertyValue = _getIndexValue(propertyValue, intElem);
332 propertyValue = _getAttributeValue(propertyValue, (String) elem);
337 propertyValue = _findProperty((String) args.get(1)).getValue();
339 if (propertyValue instanceof Function) {
340 return ((Function) propertyValue).result();
342 return getFunction(toscaTpl, context, propertyValue, toscaTpl.getResolveGetInput());
345 public String getNodeTemplateName() {
346 return (String) args.get(0);
349 public String getPropertyName() {
350 if (args.size() > 2) {
351 return (String) args.get(2);
353 return (String) args.get(1);
356 public String getReqorCap() {
357 if (args.size() > 2) {
358 return (String) args.get(1);
367 class GetProperty(Function):
368 """Get a property value of an entity defined in the same service template.
372 * Node template name | SELF | HOST | SOURCE | TARGET.
373 * Requirement or capability name (optional).
376 If requirement or capability name is specified, the behavior is as follows:
377 The req or cap name is first looked up in the specified node template's
379 If found, it would search for a matching capability
380 of an other node template and get its property as specified in function
382 Otherwise, the req or cap name would be looked up in the specified
383 node template's capabilities and if found, it would return the property of
384 the capability as specified in function arguments.
388 * { get_property: [ mysql_server, port ] }
389 * { get_property: [ SELF, db_port ] }
390 * { get_property: [ SELF, database_endpoint, port ] }
391 * { get_property: [ SELF, database_endpoint, port, 1 ] }
395 if len(self.args) < 2:
396 ValidationIssueCollector.appendException(
398 'Expected arguments: "node-template-name", "req-or-cap" '
399 '(optional), "property name".')))
401 if len(self.args) == 2:
402 found_prop = self._find_property(self.args[1])
405 prop = found_prop.value
406 if not isinstance(prop, Function):
407 get_function(self.tosca_tpl, self.context, prop)
408 elif len(self.args) >= 3:
409 # do not use _find_property to avoid raise KeyError
410 # if the prop is not found
411 # First check if there is property with this name
412 node_tpl = self._find_node_template(self.args[0])
413 props = node_tpl.get_properties() if node_tpl else []
415 found = [props[self.args[1]]] if self.args[1] in props else []
417 property_value = found[0].value
420 # then check the req or caps
421 property_value = self._find_req_or_cap_property(self.args[1],
423 if len(self.args) > index:
424 for elem in self.args[index:]:
425 if isinstance(property_value, list):
427 property_value = self._get_index_value(property_value,
430 property_value = self._get_attribute_value(
434 def _find_req_or_cap_property(self, req_or_cap, property_name):
435 node_tpl = self._find_node_template(self.args[0])
436 # Find property in node template's requirements
437 for r in node_tpl.requirements:
438 for req, node_name in r.items():
439 if req == req_or_cap:
440 node_template = self._find_node_template(node_name)
441 return self._get_capability_property(
445 # If requirement was not found, look in node template's capabilities
446 return self._get_capability_property(node_tpl,
450 def _get_capability_property(self,
454 """Gets a node template capability property."""
455 caps = node_template.get_capabilities()
456 if caps and capability_name in caps.keys():
457 cap = caps[capability_name]
459 props = cap.get_properties()
460 if props and property_name in props.keys():
461 property = props[property_name].value
463 ValidationIssueCollector.appendException(
464 KeyError(_('Property "%(prop)s" was not found in '
465 'capability "%(cap)s" of node template '
466 '"%(ntpl1)s" referenced from node template '
467 '"%(ntpl2)s".') % {'prop': property_name,
468 'cap': capability_name,
469 'ntpl1': node_template.name,
470 'ntpl2': self.context.name}))
472 msg = _('Requirement/CapabilityAssignment "{0}" referenced from node template '
473 '"{1}" was not found in node template "{2}".').format(
477 ValidationIssueCollector.appendException(KeyError(msg))
479 def _find_property(self, property_name):
480 node_tpl = self._find_node_template(self.args[0])
483 props = node_tpl.get_properties()
484 found = [props[property_name]] if property_name in props else []
486 ValidationIssueCollector.appendException(
487 KeyError(_('Property "%(prop)s" was not found in node '
488 'template "%(ntpl)s".') %
489 {'prop': property_name,
490 'ntpl': node_tpl.name}))
494 def _find_node_template(self, node_template_name):
495 if node_template_name == SELF:
497 # enable the HOST value in the function
498 if node_template_name == HOST:
499 return self._find_host_containing_property()
500 if node_template_name == TARGET:
501 if not isinstance(self.context.type_definition, RelationshipType):
502 ValidationIssueCollector.appendException(
503 KeyError(_('"TARGET" keyword can only be used in context'
504 ' to "Relationships" target node')))
506 return self.context.target
507 if node_template_name == SOURCE:
508 if not isinstance(self.context.type_definition, RelationshipType):
509 ValidationIssueCollector.appendException(
510 KeyError(_('"SOURCE" keyword can only be used in context'
511 ' to "Relationships" source node')))
513 return self.context.source
514 if not hasattr(self.tosca_tpl, 'nodetemplates'):
516 for node_template in self.tosca_tpl.nodetemplates:
517 if node_template.name == node_template_name:
519 ValidationIssueCollector.appendException(
521 'Node template "{0}" was not found.'
522 ).format(node_template_name)))
524 def _get_index_value(self, value, index):
525 if isinstance(value, list):
526 if index < len(value):
529 ValidationIssueCollector.appendException(
531 "Property '{0}' found in capability '{1}'"
532 " referenced from node template {2}"
533 " must have an element with index {3}.").
539 ValidationIssueCollector.appendException(
541 "Property '{0}' found in capability '{1}'"
542 " referenced from node template {2}"
543 " must be a list.").format(self.args[2],
547 def _get_attribute_value(self, value, attibute):
548 if isinstance(value, dict):
549 if attibute in value:
550 return value[attibute]
552 ValidationIssueCollector.appendException(
554 "Property '{0}' found in capability '{1}'"
555 " referenced from node template {2}"
556 " must have an attribute named {3}.").
562 ValidationIssueCollector.appendException(
564 "Property '{0}' found in capability '{1}'"
565 " referenced from node template {2}"
566 " must be a dict.").format(self.args[2],
570 # Add this functions similar to get_attribute case
571 def _find_host_containing_property(self, node_template_name=SELF):
572 node_template = self._find_node_template(node_template_name)
573 hosted_on_rel = EntityType.TOSCA_DEF[HOSTED_ON]
574 for r in node_template.requirements:
575 for requirement, target_name in r.items():
576 target_node = self._find_node_template(target_name)
577 target_type = target_node.type_definition
578 for capability in target_type.get_capabilities_objects():
579 if capability.type in hosted_on_rel['valid_target_types']:
580 if self._property_exists_in_type(target_type):
582 return self._find_host_containing_property(
586 def _property_exists_in_type(self, type_definition):
587 props_def = type_definition.get_properties_def()
588 found = [props_def[self.args[1]]] \
589 if self.args[1] in props_def else []
590 return len(found) == 1
593 if len(self.args) >= 3:
594 # First check if there is property with this name
595 node_tpl = self._find_node_template(self.args[0])
596 props = node_tpl.get_properties() if node_tpl else []
598 found = [props[self.args[1]]] if self.args[1] in props else []
600 property_value = found[0].value
603 # then check the req or caps
604 property_value = self._find_req_or_cap_property(self.args[1],
606 if len(self.args) > index:
607 for elem in self.args[index:]:
608 if isinstance(property_value, list):
610 property_value = self._get_index_value(property_value,
613 property_value = self._get_attribute_value(
617 property_value = self._find_property(self.args[1]).value
618 if isinstance(property_value, Function):
619 return property_value.result()
620 return get_function(self.tosca_tpl,
625 def node_template_name(self):
629 def property_name(self):
630 if len(self.args) > 2:
635 def req_or_cap(self):
636 if len(self.args) > 2: