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.elements;
23 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
24 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
26 import java.util.ArrayList;
27 import java.util.LinkedHashMap;
30 public class NodeType extends StatefulEntityType {
31 // TOSCA built-in node type
33 private static final String DERIVED_FROM = "derived_from";
34 private static final String METADATA = "metadata";
35 private static final String PROPERTIES = "properties";
36 private static final String VERSION = "version";
37 private static final String DESCRIPTION = "description";
38 private static final String ATTRIBUTES = "attributes";
39 private static final String REQUIREMENTS = "requirements";
40 private static final String CAPABILITIES = "capabilities";
41 private static final String INTERFACES = "interfaces";
42 private static final String ARTIFACTS = "artifacts";
44 private static final String SECTIONS[] = {
45 DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, ATTRIBUTES, REQUIREMENTS, CAPABILITIES, INTERFACES, ARTIFACTS
49 public LinkedHashMap<String, Object> customDef;
51 public NodeType(String nttype, LinkedHashMap<String, Object> ntcustomDef) {
52 super(nttype, NODE_PREFIX, ntcustomDef);
54 customDef = ntcustomDef;
58 public Object getParentType() {
59 // Return a node this node is derived from
63 String pnode = derivedFrom(defs);
64 if (pnode != null && !pnode.isEmpty()) {
65 return new NodeType(pnode, customDef);
70 @SuppressWarnings("unchecked")
71 public LinkedHashMap<RelationshipType, NodeType> getRelationship() {
72 // Return a dictionary of relationships to other node types
74 // This method returns a dictionary of named relationships that nodes
75 // of the current node type (self) can have to other nodes (of specific
76 // types) in a TOSCA template.
78 LinkedHashMap<RelationshipType, NodeType> relationship = new LinkedHashMap<>();
79 ArrayList<LinkedHashMap<String, Object>> requires;
80 Object treq = getAllRequirements();
82 // NOTE(sdmonov): Check if requires is a dict.
83 // If it is a dict convert it to a list of dicts.
84 // This is needed because currently the code below supports only
85 // lists as requirements definition. The following check will
86 // make sure if a map (dict) was provided it will be converted to
87 // a list before proceeding to the parsing.
88 if (treq instanceof LinkedHashMap) {
89 requires = new ArrayList<>();
90 for (Map.Entry<String, Object> me : ((LinkedHashMap<String, Object>) treq).entrySet()) {
91 LinkedHashMap<String, Object> tl = new LinkedHashMap<>();
92 tl.put(me.getKey(), me.getValue());
96 requires = (ArrayList<LinkedHashMap<String, Object>>) treq;
99 String keyword = null;
100 String nodeType = null;
101 for (LinkedHashMap<String, Object> require : requires) {
102 String relation = null;
103 for (Map.Entry<String, Object> re : require.entrySet()) {
104 String key = re.getKey();
105 LinkedHashMap<String, Object> req = (LinkedHashMap<String, Object>) re.getValue();
106 if (req.get("relationship") != null) {
107 Object trelation = req.get("relationship");
108 // trelation is a string or a dict with "type" mapped to the string we want
109 if (trelation instanceof String) {
110 relation = (String) trelation;
112 if (((LinkedHashMap<String, Object>) trelation).get("type") != null) {
113 relation = (String) ((LinkedHashMap<String, Object>) trelation).get("type");
116 nodeType = (String) req.get("node");
117 //BUG meaningless?? LinkedHashMap<String,Object> value = req;
118 if (nodeType != null) {
121 String getRelation = null;
122 // If nodeTypeByCap is a dict and has a type key
123 // we need to lookup the node type using
124 // the capability type
125 String captype = (String) req.get("capability");
126 nodeType = _getNodeTypeByCap(captype);
127 if (nodeType != null) {
128 getRelation = _getRelation(key, nodeType);
130 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE11", String.format(
131 "NodeTypeRequirementForCapabilityUnfulfilled: Node type: \"%s\" with requrement \"%s\" for node type with capability type \"%s\" is not found\\unfulfilled", this.ntype, key, captype)));
133 if (getRelation != null) {
134 relation = getRelation;
140 if (relation == null || nodeType == null) {
141 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE11", String.format(
142 "NodeTypeForRelationUnfulfilled: Node type \"%s\" - relationship type \"%s\" is unfulfilled", this.ntype, relation)));
144 RelationshipType rtype = new RelationshipType(relation, keyword, customDef);
145 NodeType relatednode = new NodeType(nodeType, customDef);
146 relationship.put(rtype, relatednode);
154 @SuppressWarnings("unchecked")
155 private String _getNodeTypeByCap(String cap) {
156 // Find the node type that has the provided capability
158 // This method will lookup all node types if they have the
159 // provided capability.
160 // Filter the node types
161 ArrayList<String> nodeTypes = new ArrayList<>();
162 for (String nt : customDef.keySet()) {
163 if (nt.startsWith(NODE_PREFIX) || nt.startsWith("org.openecomp") && !nt.equals("tosca.nodes.Root")) {
167 for (String nt : nodeTypes) {
168 LinkedHashMap<String, Object> nodeDef = (LinkedHashMap<String, Object>) customDef.get(nt);
169 if (nodeDef instanceof LinkedHashMap && nodeDef.get("capabilities") != null) {
170 LinkedHashMap<String, Object> nodeCaps = (LinkedHashMap<String, Object>) nodeDef.get("capabilities");
171 if (nodeCaps != null) {
172 for (Object val : nodeCaps.values()) {
173 if (val instanceof LinkedHashMap) {
174 String tp = (String) ((LinkedHashMap<String, Object>) val).get("type");
175 if (tp != null && tp.equals(cap)) {
186 @SuppressWarnings("unchecked")
187 private String _getRelation(String key, String ndtype) {
188 String relation = null;
189 NodeType ntype = new NodeType(ndtype, customDef);
190 LinkedHashMap<String, CapabilityTypeDef> caps = ntype.getCapabilities();
191 if (caps != null && caps.get(key) != null) {
192 CapabilityTypeDef c = caps.get(key);
193 for (int i = 0; i < RELATIONSHIP_TYPE.length; i++) {
194 String r = RELATIONSHIP_TYPE[i];
199 LinkedHashMap<String, Object> rtypedef = (LinkedHashMap<String, Object>) customDef.get(r);
200 for (Object o : rtypedef.values()) {
201 LinkedHashMap<String, Object> properties = (LinkedHashMap<String, Object>) o;
202 if (properties.get(c.getType()) != null) {
207 if (relation != null) {
210 for (Object o : rtypedef.values()) {
211 LinkedHashMap<String, Object> properties = (LinkedHashMap<String, Object>) o;
212 if (properties.get(c.getParentType()) != null) {
223 @SuppressWarnings("unchecked")
224 public ArrayList<CapabilityTypeDef> getCapabilitiesObjects() {
225 // Return a list of capability objects
226 ArrayList<CapabilityTypeDef> typecapabilities = new ArrayList<>();
227 LinkedHashMap<String, Object> caps = (LinkedHashMap<String, Object>) getValue(CAPABILITIES, null, true);
229 // 'cname' is symbolic name of the capability
230 // 'cvalue' is a dict { 'type': <capability type name> }
231 for (Map.Entry<String, Object> me : caps.entrySet()) {
232 String cname = me.getKey();
233 LinkedHashMap<String, String> cvalue = (LinkedHashMap<String, String>) me.getValue();
234 String ctype = cvalue.get("type");
235 CapabilityTypeDef cap = new CapabilityTypeDef(cname, ctype, type, customDef);
236 typecapabilities.add(cap);
239 return typecapabilities;
242 public LinkedHashMap<String, CapabilityTypeDef> getCapabilities() {
243 // Return a dictionary of capability name-objects pairs
244 LinkedHashMap<String, CapabilityTypeDef> caps = new LinkedHashMap<>();
245 for (CapabilityTypeDef ctd : getCapabilitiesObjects()) {
246 caps.put(ctd.getName(), ctd);
251 @SuppressWarnings("unchecked")
252 public ArrayList<Object> getRequirements() {
253 return (ArrayList<Object>) getValue(REQUIREMENTS, null, true);
256 public ArrayList<Object> getAllRequirements() {
257 return getRequirements();
260 @SuppressWarnings("unchecked")
261 public LinkedHashMap<String, Object> getInterfaces() {
262 return (LinkedHashMap<String, Object>) getValue(INTERFACES, null, false);
266 @SuppressWarnings("unchecked")
267 public ArrayList<String> getLifecycleInputs() {
268 // Return inputs to life cycle operations if found
269 ArrayList<String> inputs = new ArrayList<>();
270 LinkedHashMap<String, Object> interfaces = getInterfaces();
271 if (interfaces != null) {
272 for (Map.Entry<String, Object> me : interfaces.entrySet()) {
273 String iname = me.getKey();
274 LinkedHashMap<String, Object> ivalue = (LinkedHashMap<String, Object>) me.getValue();
275 if (iname.equals(InterfacesDef.LIFECYCLE)) {
276 for (Map.Entry<String, Object> ie : ivalue.entrySet()) {
277 if (ie.getKey().equals("input")) {
278 LinkedHashMap<String, Object> y = (LinkedHashMap<String, Object>) ie.getValue();
279 for (String i : y.keySet()) {
290 public ArrayList<String> getLifecycleOperations() {
291 // Return available life cycle operations if found
292 ArrayList<String> ops = null;
293 LinkedHashMap<String, Object> interfaces = getInterfaces();
294 if (interfaces != null) {
295 InterfacesDef i = new InterfacesDef(this, InterfacesDef.LIFECYCLE, null, null, null);
296 ops = i.getLifecycleOps();
301 public CapabilityTypeDef getCapability(String name) {
302 //BUG?? the python code has to be wrong
303 // it refers to a bad attribute 'value'...
304 LinkedHashMap<String, CapabilityTypeDef> caps = getCapabilities();
306 return caps.get(name);
310 def get_capability(self, name):
311 caps = self.get_capabilities()
312 if caps and name in caps.keys():
313 return caps[name].value
317 public String getCapabilityType(String name) {
318 //BUG?? the python code has to be wrong
319 // it refers to a bad attribute 'value'...
320 CapabilityTypeDef captype = getCapability(name);
321 if (captype != null) {
322 return captype.getType();
326 def get_capability_type(self, name):
327 captype = self.get_capability(name)
328 if captype and name in captype.keys():
329 return captype[name].value
333 private void _validateKeys() {
335 for (String key : defs.keySet()) {
336 boolean bFound = false;
337 for (int i = 0; i < SECTIONS.length; i++) {
338 if (key.equals(SECTIONS[i])) {
344 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE124", String.format(
345 "UnknownFieldError: Nodetype \"%s\" has unknown field \"%s\"", ntype, key)));
355 from toscaparser.common.exception import ValidationIssueCollector
356 from toscaparser.common.exception import UnknownFieldError
357 from toscaparser.elements.capabilitytype import CapabilityTypeDef
358 import org.openecomp.sdc.toscaparser.api.elements.interfaces as ifaces
359 from toscaparser.elements.interfaces import InterfacesDef
360 from toscaparser.elements.relationshiptype import RelationshipType
361 from toscaparser.elements.statefulentitytype import StatefulEntityType
364 class NodeType(StatefulEntityType):
365 '''TOSCA built-in node type.'''
366 SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, ATTRIBUTES, REQUIREMENTS, CAPABILITIES, INTERFACES, ARTIFACTS) = \
367 ('derived_from', 'metadata', 'properties', 'version',
368 'description', 'attributes', 'requirements', 'capabilities',
369 'interfaces', 'artifacts')
371 def __init__(self, ntype, custom_def=None):
372 super(NodeType, self).__init__(ntype, self.NODE_PREFIX, custom_def)
374 self.custom_def = custom_def
375 self._validate_keys()
378 def parent_type(self):
379 '''Return a node this node is derived from.'''
380 if not hasattr(self, 'defs'):
382 pnode = self.derived_from(self.defs)
384 return NodeType(pnode, self.custom_def)
387 def relationship(self):
388 '''Return a dictionary of relationships to other node types.
390 This method returns a dictionary of named relationships that nodes
391 of the current node type (self) can have to other nodes (of specific
392 types) in a TOSCA template.
396 requires = self.get_all_requirements()
398 # NOTE(sdmonov): Check if requires is a dict.
399 # If it is a dict convert it to a list of dicts.
400 # This is needed because currently the code below supports only
401 # lists as requirements definition. The following check will
402 # make sure if a map (dict) was provided it will be converted to
403 # a list before proceeding to the parsing.
404 if isinstance(requires, dict):
405 requires = [{key: value} for key, value in requires.items()]
409 for require in requires:
410 for key, req in require.items():
411 if 'relationship' in req:
412 relation = req.get('relationship')
413 if 'type' in relation:
414 relation = relation.get('type')
415 node_type = req.get('node')
420 # If value is a dict and has a type key
421 # we need to lookup the node type using
422 # the capability type
424 if isinstance(value, dict):
425 captype = value['capability']
427 _get_node_type_by_cap(key, captype))
428 relation = self._get_relation(key, value)
431 rtype = RelationshipType(relation, keyword, self.custom_def)
432 relatednode = NodeType(node_type, self.custom_def)
433 relationship[rtype] = relatednode
436 def _get_node_type_by_cap(self, key, cap):
437 '''Find the node type that has the provided capability
439 This method will lookup all node types if they have the
443 # Filter the node types
444 node_types = [node_type for node_type in self.TOSCA_DEF.keys()
445 if node_type.startswith(self.NODE_PREFIX) and
446 node_type != 'tosca.nodes.Root']
448 for node_type in node_types:
449 node_def = self.TOSCA_DEF[node_type]
450 if isinstance(node_def, dict) and 'capabilities' in node_def:
451 node_caps = node_def['capabilities']
452 for value in node_caps.values():
453 if isinstance(value, dict) and \
454 'type' in value and value['type'] == cap:
457 def _get_relation(self, key, ndtype):
459 ntype = NodeType(ndtype)
460 caps = ntype.get_capabilities()
461 if caps and key in caps.keys():
463 for r in self.RELATIONSHIP_TYPE:
464 rtypedef = ntype.TOSCA_DEF[r]
465 for properties in rtypedef.values():
466 if c.type in properties:
472 for properties in rtypedef.values():
473 if c.parent_type in properties:
478 def get_capabilities_objects(self):
479 '''Return a list of capability objects.'''
480 typecapabilities = []
481 caps = self.get_value(self.CAPABILITIES, None, True)
483 # 'name' is symbolic name of the capability
484 # 'value' is a dict { 'type': <capability type name> }
485 for name, value in caps.items():
486 ctype = value.get('type')
487 cap = CapabilityTypeDef(name, ctype, self.type,
489 typecapabilities.append(cap)
490 return typecapabilities
492 def get_capabilities(self):
493 '''Return a dictionary of capability name-objects pairs.'''
494 return {cap.name: cap
495 for cap in self.get_capabilities_objects()}
498 def requirements(self):
499 return self.get_value(self.REQUIREMENTS, None, True)
501 def get_all_requirements(self):
502 return self.requirements
505 def interfaces(self):
506 return self.get_value(self.INTERFACES)
509 def lifecycle_inputs(self):
510 '''Return inputs to life cycle operations if found.'''
512 interfaces = self.interfaces
514 for name, value in interfaces.items():
515 if name == ifaces.LIFECYCLE:
516 for x, y in value.items():
518 for i in y.iterkeys():
523 def lifecycle_operations(self):
524 '''Return available life cycle operations if found.'''
526 interfaces = self.interfaces
528 i = InterfacesDef(self.type, ifaces.LIFECYCLE)
529 ops = i.lifecycle_ops
532 def get_capability(self, name):
533 caps = self.get_capabilities()
534 if caps and name in caps.keys():
535 return caps[name].value
537 def get_capability_type(self, name):
538 captype = self.get_capability(name)
539 if captype and name in captype.keys():
540 return captype[name].value
542 def _validate_keys(self):
544 for key in self.defs.keys():
545 if key not in self.SECTIONS:
546 ValidationIssueCollector.appendException(
547 UnknownFieldError(what='Nodetype"%s"' % self.ntype,