package org.openecomp.sdc.toscaparser.api.elements; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; import org.openecomp.sdc.toscaparser.api.common.ExceptionCollector; import org.openecomp.sdc.toscaparser.api.elements.InterfacesDef; public class NodeType extends StatefulEntityType { // TOSCA built-in node type private static final String DERIVED_FROM = "derived_from"; private static final String METADATA = "metadata"; private static final String PROPERTIES = "properties"; private static final String VERSION = "version"; private static final String DESCRIPTION = "description"; private static final String ATTRIBUTES = "attributes"; private static final String REQUIREMENTS = "requirements"; private static final String CAPABILITIES = "capabilities"; private static final String INTERFACES = "interfaces"; private static final String ARTIFACTS = "artifacts"; private static final String SECTIONS[] = { DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, ATTRIBUTES, REQUIREMENTS, CAPABILITIES, INTERFACES, ARTIFACTS }; private String ntype; public LinkedHashMap customDef; public NodeType(String nttype,LinkedHashMap ntcustomDef) { super(nttype,NODE_PREFIX, ntcustomDef); ntype = nttype; customDef = ntcustomDef; _validateKeys(); } public Object getParentType() { // Return a node this node is derived from if(defs == null) { return null; } String pnode = derivedFrom(defs); if(pnode != null && !pnode.isEmpty()) { return new NodeType(pnode,customDef); } return null; } @SuppressWarnings("unchecked") public LinkedHashMap getRelationship() { // Return a dictionary of relationships to other node types // This method returns a dictionary of named relationships that nodes // of the current node type (self) can have to other nodes (of specific // types) in a TOSCA template. LinkedHashMap relationship = new LinkedHashMap<>(); ArrayList> requires; Object treq = getAllRequirements(); if(treq != null) { // NOTE(sdmonov): Check if requires is a dict. // If it is a dict convert it to a list of dicts. // This is needed because currently the code below supports only // lists as requirements definition. The following check will // make sure if a map (dict) was provided it will be converted to // a list before proceeding to the parsing. if(treq instanceof LinkedHashMap) { requires = new ArrayList<>(); for(Map.Entry me: ((LinkedHashMap)treq).entrySet()) { LinkedHashMap tl = new LinkedHashMap<>(); tl.put(me.getKey(),me.getValue()); requires.add(tl); } } else { requires = (ArrayList>)treq; } String keyword = null; String nodeType = null; for(LinkedHashMap require: requires) { String relation = null; for(Map.Entry re: require.entrySet()) { String key = re.getKey(); LinkedHashMap req = (LinkedHashMap)re.getValue(); if(req.get("relationship") != null) { Object trelation = req.get("relationship"); // trelation is a string or a dict with "type" mapped to the string we want if(trelation instanceof String) { relation = (String)trelation; } else { if(((LinkedHashMap)trelation).get("type") != null) { relation = (String)((LinkedHashMap)trelation).get("type"); } } nodeType = (String)req.get("node"); //BUG meaningless?? LinkedHashMap value = req; if(nodeType != null) { keyword = "node"; } else { // If value is a dict and has a type key // we need to lookup the node type using // the capability type String captype = (String)req.get("capability"); String value = _getNodeTypeByCap(captype); String getRelation = _getRelation(key,value); if (getRelation != null) { relation = getRelation; } keyword = key; nodeType = value; } } } RelationshipType rtype = new RelationshipType(relation, keyword, customDef); NodeType relatednode = new NodeType(nodeType, customDef); relationship.put(rtype, relatednode); } } return relationship; } @SuppressWarnings("unchecked") private String _getNodeTypeByCap(String cap) { // Find the node type that has the provided capability // This method will lookup all node types if they have the // provided capability. // Filter the node types ArrayList nodeTypes = new ArrayList<>(); for(String nt: TOSCA_DEF.keySet()) { if(nt.startsWith(NODE_PREFIX) && !nt.equals("tosca.nodes.Root")) { nodeTypes.add(nt); } } for(String nt: nodeTypes) { LinkedHashMap nodeDef = (LinkedHashMap)TOSCA_DEF.get(nt); if(nodeDef instanceof LinkedHashMap && nodeDef.get("capabilities") != null) { LinkedHashMap nodeCaps = (LinkedHashMap)nodeDef.get("capabilities"); if(nodeCaps != null) { for(Object val: nodeCaps.values()) { if(val instanceof LinkedHashMap) { String tp = (String)((LinkedHashMap)val).get("type"); if(tp != null && tp.equals(cap)) { return nt; } } } } } } return null; } @SuppressWarnings("unchecked") private String _getRelation(String key,String ndtype) { String relation = null; NodeType ntype = new NodeType(ndtype,null); LinkedHashMap caps = ntype.getCapabilities(); if(caps != null && caps.get(key) != null) { CapabilityTypeDef c = caps.get(key); for(int i=0; i< RELATIONSHIP_TYPE.length; i++) { String r = RELATIONSHIP_TYPE[i]; LinkedHashMap rtypedef = (LinkedHashMap)TOSCA_DEF.get(r); for(Object o: rtypedef.values()) { LinkedHashMap properties = (LinkedHashMap)o; if(properties.get(c.getType()) != null) { relation = r; break; } } if(relation != null) { break; } else { for(Object o: rtypedef.values()) { LinkedHashMap properties = (LinkedHashMap)o; if(properties.get(c.getParentType()) != null) { relation = r; break; } } } } } return relation; } @SuppressWarnings("unchecked") public ArrayList getCapabilitiesObjects() { // Return a list of capability objects ArrayList typecapabilities = new ArrayList<>(); LinkedHashMap caps = (LinkedHashMap)getValue(CAPABILITIES, null, true); if(caps != null) { // 'cname' is symbolic name of the capability // 'cvalue' is a dict { 'type': } for(Map.Entry me: caps.entrySet()) { String cname = me.getKey(); LinkedHashMap cvalue = (LinkedHashMap)me.getValue(); String ctype = cvalue.get("type"); CapabilityTypeDef cap = new CapabilityTypeDef(cname,ctype,type,customDef); typecapabilities.add(cap); } } return typecapabilities; } public LinkedHashMap getCapabilities() { // Return a dictionary of capability name-objects pairs LinkedHashMap caps = new LinkedHashMap<>(); for(CapabilityTypeDef ctd: getCapabilitiesObjects()) { caps.put(ctd.getName(),ctd); } return caps; } @SuppressWarnings("unchecked") public ArrayList getRequirements() { return (ArrayList)getValue(REQUIREMENTS,null,true); } public ArrayList getAllRequirements() { return getRequirements(); } @SuppressWarnings("unchecked") public LinkedHashMap getInterfaces() { return (LinkedHashMap)getValue(INTERFACES,null,false); } @SuppressWarnings("unchecked") public ArrayList getLifecycleInputs() { // Return inputs to life cycle operations if found ArrayList inputs = new ArrayList<>(); LinkedHashMap interfaces = getInterfaces(); if(interfaces != null) { for(Map.Entry me: interfaces.entrySet()) { String iname = me.getKey(); LinkedHashMap ivalue = (LinkedHashMap)me.getValue(); if(iname.equals(InterfacesDef.LIFECYCLE)) { for(Map.Entry ie: ivalue.entrySet()) { if(ie.getKey().equals("input")) { LinkedHashMap y = (LinkedHashMap)ie.getValue(); for(String i: y.keySet()) { inputs.add(i); } } } } } } return inputs; } public ArrayList getLifecycleOperations() { // Return available life cycle operations if found ArrayList ops = null; LinkedHashMap interfaces = getInterfaces(); if(interfaces != null) { InterfacesDef i = new InterfacesDef(this,InterfacesDef.LIFECYCLE,null,null,null); ops = i.getLifecycleOps(); } return ops; } public CapabilityTypeDef getCapability(String name) { //BUG?? the python code has to be wrong // it refers to a bad attribute 'value'... LinkedHashMap caps = getCapabilities(); if(caps != null) { return caps.get(name); } return null; /* def get_capability(self, name): caps = self.get_capabilities() if caps and name in caps.keys(): return caps[name].value */ } public String getCapabilityType(String name) { //BUG?? the python code has to be wrong // it refers to a bad attribute 'value'... CapabilityTypeDef captype = getCapability(name); if(captype != null) { return captype.getType(); } return null; /* def get_capability_type(self, name): captype = self.get_capability(name) if captype and name in captype.keys(): return captype[name].value */ } private void _validateKeys() { if(defs != null) { for(String key: defs.keySet()) { boolean bFound = false; for(int i=0; i< SECTIONS.length; i++) { if(key.equals(SECTIONS[i])) { bFound = true; break; } } if(!bFound) { ExceptionCollector.appendException(String.format( "UnknownFieldError: Nodetype \"%s\" has unknown field \"%s\"",ntype,key)); } } } } } /*python from toscaparser.common.exception import ExceptionCollector from toscaparser.common.exception import UnknownFieldError from toscaparser.elements.capabilitytype import CapabilityTypeDef import org.openecomp.sdc.toscaparser.api.elements.interfaces as ifaces from toscaparser.elements.interfaces import InterfacesDef from toscaparser.elements.relationshiptype import RelationshipType from toscaparser.elements.statefulentitytype import StatefulEntityType class NodeType(StatefulEntityType): '''TOSCA built-in node type.''' SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, ATTRIBUTES, REQUIREMENTS, CAPABILITIES, INTERFACES, ARTIFACTS) = \ ('derived_from', 'metadata', 'properties', 'version', 'description', 'attributes', 'requirements', 'capabilities', 'interfaces', 'artifacts') def __init__(self, ntype, custom_def=None): super(NodeType, self).__init__(ntype, self.NODE_PREFIX, custom_def) self.ntype = ntype self.custom_def = custom_def self._validate_keys() @property def parent_type(self): '''Return a node this node is derived from.''' if not hasattr(self, 'defs'): return None pnode = self.derived_from(self.defs) if pnode: return NodeType(pnode, self.custom_def) @property def relationship(self): '''Return a dictionary of relationships to other node types. This method returns a dictionary of named relationships that nodes of the current node type (self) can have to other nodes (of specific types) in a TOSCA template. ''' relationship = {} requires = self.get_all_requirements() if requires: # NOTE(sdmonov): Check if requires is a dict. # If it is a dict convert it to a list of dicts. # This is needed because currently the code below supports only # lists as requirements definition. The following check will # make sure if a map (dict) was provided it will be converted to # a list before proceeding to the parsing. if isinstance(requires, dict): requires = [{key: value} for key, value in requires.items()] keyword = None node_type = None for require in requires: for key, req in require.items(): if 'relationship' in req: relation = req.get('relationship') if 'type' in relation: relation = relation.get('type') node_type = req.get('node') value = req if node_type: keyword = 'node' else: # If value is a dict and has a type key # we need to lookup the node type using # the capability type value = req if isinstance(value, dict): captype = value['capability'] value = (self. _get_node_type_by_cap(key, captype)) relation = self._get_relation(key, value) keyword = key node_type = value rtype = RelationshipType(relation, keyword, self.custom_def) relatednode = NodeType(node_type, self.custom_def) relationship[rtype] = relatednode return relationship def _get_node_type_by_cap(self, key, cap): '''Find the node type that has the provided capability This method will lookup all node types if they have the provided capability. ''' # Filter the node types node_types = [node_type for node_type in self.TOSCA_DEF.keys() if node_type.startswith(self.NODE_PREFIX) and node_type != 'tosca.nodes.Root'] for node_type in node_types: node_def = self.TOSCA_DEF[node_type] if isinstance(node_def, dict) and 'capabilities' in node_def: node_caps = node_def['capabilities'] for value in node_caps.values(): if isinstance(value, dict) and \ 'type' in value and value['type'] == cap: return node_type def _get_relation(self, key, ndtype): relation = None ntype = NodeType(ndtype) caps = ntype.get_capabilities() if caps and key in caps.keys(): c = caps[key] for r in self.RELATIONSHIP_TYPE: rtypedef = ntype.TOSCA_DEF[r] for properties in rtypedef.values(): if c.type in properties: relation = r break if relation: break else: for properties in rtypedef.values(): if c.parent_type in properties: relation = r break return relation def get_capabilities_objects(self): '''Return a list of capability objects.''' typecapabilities = [] caps = self.get_value(self.CAPABILITIES, None, True) if caps: # 'name' is symbolic name of the capability # 'value' is a dict { 'type': } for name, value in caps.items(): ctype = value.get('type') cap = CapabilityTypeDef(name, ctype, self.type, self.custom_def) typecapabilities.append(cap) return typecapabilities def get_capabilities(self): '''Return a dictionary of capability name-objects pairs.''' return {cap.name: cap for cap in self.get_capabilities_objects()} @property def requirements(self): return self.get_value(self.REQUIREMENTS, None, True) def get_all_requirements(self): return self.requirements @property def interfaces(self): return self.get_value(self.INTERFACES) @property def lifecycle_inputs(self): '''Return inputs to life cycle operations if found.''' inputs = [] interfaces = self.interfaces if interfaces: for name, value in interfaces.items(): if name == ifaces.LIFECYCLE: for x, y in value.items(): if x == 'inputs': for i in y.iterkeys(): inputs.append(i) return inputs @property def lifecycle_operations(self): '''Return available life cycle operations if found.''' ops = None interfaces = self.interfaces if interfaces: i = InterfacesDef(self.type, ifaces.LIFECYCLE) ops = i.lifecycle_ops return ops def get_capability(self, name): caps = self.get_capabilities() if caps and name in caps.keys(): return caps[name].value def get_capability_type(self, name): captype = self.get_capability(name) if captype and name in captype.keys(): return captype[name].value def _validate_keys(self): if self.defs: for key in self.defs.keys(): if key not in self.SECTIONS: ExceptionCollector.appendException( UnknownFieldError(what='Nodetype"%s"' % self.ntype, field=key)) */