Fix checkstyle violations in sdc/jtosca
[sdc/sdc-tosca.git] / src / main / java / org / onap / sdc / toscaparser / api / elements / NodeType.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.sdc.toscaparser.api.elements;
22
23 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
24 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
25
26 import java.util.ArrayList;
27 import java.util.LinkedHashMap;
28 import java.util.Map;
29
30 public class NodeType extends StatefulEntityType {
31     // TOSCA built-in node type
32
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";
43
44     private static final String SECTIONS[] = {
45             DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, ATTRIBUTES, REQUIREMENTS, CAPABILITIES, INTERFACES, ARTIFACTS
46     };
47
48     private String ntype;
49     public LinkedHashMap<String, Object> customDef;
50
51     public NodeType(String nttype, LinkedHashMap<String, Object> ntcustomDef) {
52         super(nttype, NODE_PREFIX, ntcustomDef);
53         ntype = nttype;
54         customDef = ntcustomDef;
55         _validateKeys();
56     }
57
58     public Object getParentType() {
59         // Return a node this node is derived from
60         if (defs == null) {
61             return null;
62         }
63         String pnode = derivedFrom(defs);
64         if (pnode != null && !pnode.isEmpty()) {
65             return new NodeType(pnode, customDef);
66         }
67         return null;
68     }
69
70     @SuppressWarnings("unchecked")
71     public LinkedHashMap<RelationshipType, NodeType> getRelationship() {
72         // Return a dictionary of relationships to other node types
73
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.
77
78         LinkedHashMap<RelationshipType, NodeType> relationship = new LinkedHashMap<>();
79         ArrayList<LinkedHashMap<String, Object>> requires;
80         Object treq = getAllRequirements();
81         if (treq != null) {
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());
93                     requires.add(tl);
94                 }
95             } else {
96                 requires = (ArrayList<LinkedHashMap<String, Object>>) treq;
97             }
98
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;
111                         } else {
112                             if (((LinkedHashMap<String, Object>) trelation).get("type") != null) {
113                                 relation = (String) ((LinkedHashMap<String, Object>) trelation).get("type");
114                             }
115                         }
116                         nodeType = (String) req.get("node");
117                         //BUG meaningless?? LinkedHashMap<String,Object> value = req;
118                         if (nodeType != null) {
119                             keyword = "node";
120                         } else {
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);
129                             } else {
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)));
132                             }
133                             if (getRelation != null) {
134                                 relation = getRelation;
135                             }
136                             keyword = key;
137                         }
138                     }
139                 }
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)));
143                 } else {
144                     RelationshipType rtype = new RelationshipType(relation, keyword, customDef);
145                     NodeType relatednode = new NodeType(nodeType, customDef);
146                     relationship.put(rtype, relatednode);
147                 }
148             }
149         }
150         return relationship;
151
152     }
153
154     @SuppressWarnings("unchecked")
155     private String _getNodeTypeByCap(String cap) {
156         // Find the node type that has the provided capability
157
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")) {
164                 nodeTypes.add(nt);
165             }
166         }
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)) {
176                                 return nt;
177                             }
178                         }
179                     }
180                 }
181             }
182         }
183         return null;
184     }
185
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];
195                 if (r != null) {
196                     relation = r;
197                     break;
198                 }
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) {
203                         relation = r;
204                         break;
205                     }
206                 }
207                 if (relation != null) {
208                     break;
209                 } else {
210                     for (Object o : rtypedef.values()) {
211                         LinkedHashMap<String, Object> properties = (LinkedHashMap<String, Object>) o;
212                         if (properties.get(c.getParentType()) != null) {
213                             relation = r;
214                             break;
215                         }
216                     }
217                 }
218             }
219         }
220         return relation;
221     }
222
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);
228         if (caps != null) {
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);
237             }
238         }
239         return typecapabilities;
240     }
241
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);
247         }
248         return caps;
249     }
250
251     @SuppressWarnings("unchecked")
252     public ArrayList<Object> getRequirements() {
253         return (ArrayList<Object>) getValue(REQUIREMENTS, null, true);
254     }
255
256     public ArrayList<Object> getAllRequirements() {
257         return getRequirements();
258     }
259
260     @SuppressWarnings("unchecked")
261     public LinkedHashMap<String, Object> getInterfaces() {
262         return (LinkedHashMap<String, Object>) getValue(INTERFACES, null, false);
263     }
264
265
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()) {
280                                 inputs.add(i);
281                             }
282                         }
283                     }
284                 }
285             }
286         }
287         return inputs;
288     }
289
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();
297         }
298         return ops;
299     }
300
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();
305         if (caps != null) {
306             return caps.get(name);
307         }
308         return null;
309                 /*
310             def get_capability(self, name):
311                 caps = self.get_capabilities()
312                 if caps and name in caps.keys():
313                     return caps[name].value
314                 */
315     }
316
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();
323         }
324         return null;
325             /*          
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
330              */
331     }
332
333     private void _validateKeys() {
334         if (defs != null) {
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])) {
339                         bFound = true;
340                         break;
341                     }
342                 }
343                 if (!bFound) {
344                     ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE124", String.format(
345                             "UnknownFieldError: Nodetype \"%s\" has unknown field \"%s\"", ntype, key)));
346                 }
347             }
348         }
349     }
350
351 }
352
353 /*python
354
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
362
363
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')
370
371     def __init__(self, ntype, custom_def=None):
372         super(NodeType, self).__init__(ntype, self.NODE_PREFIX, custom_def)
373         self.ntype = ntype
374         self.custom_def = custom_def
375         self._validate_keys()
376
377     @property
378     def parent_type(self):
379         '''Return a node this node is derived from.'''
380         if not hasattr(self, 'defs'):
381             return None
382         pnode = self.derived_from(self.defs)
383         if pnode:
384             return NodeType(pnode, self.custom_def)
385
386     @property
387     def relationship(self):
388         '''Return a dictionary of relationships to other node types.
389
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.
393
394         '''
395         relationship = {}
396         requires = self.get_all_requirements()
397         if requires:
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()]
406
407             keyword = None
408             node_type = None
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')
416                         value = req
417                         if node_type:
418                             keyword = 'node'
419                         else:
420                             # If value is a dict and has a type key
421                             # we need to lookup the node type using
422                             # the capability type
423                             value = req
424                             if isinstance(value, dict):
425                                 captype = value['capability']
426                                 value = (self.
427                                          _get_node_type_by_cap(key, captype))
428                             relation = self._get_relation(key, value)
429                             keyword = key
430                             node_type = value
431                 rtype = RelationshipType(relation, keyword, self.custom_def)
432                 relatednode = NodeType(node_type, self.custom_def)
433                 relationship[rtype] = relatednode
434         return relationship
435
436     def _get_node_type_by_cap(self, key, cap):
437         '''Find the node type that has the provided capability
438
439         This method will lookup all node types if they have the
440         provided capability.
441         '''
442
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']
447
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:
455                         return node_type
456
457     def _get_relation(self, key, ndtype):
458         relation = None
459         ntype = NodeType(ndtype)
460         caps = ntype.get_capabilities()
461         if caps and key in caps.keys():
462             c = caps[key]
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:
467                         relation = r
468                         break
469                 if relation:
470                     break
471                 else:
472                     for properties in rtypedef.values():
473                         if c.parent_type in properties:
474                             relation = r
475                             break
476         return relation
477
478     def get_capabilities_objects(self):
479         '''Return a list of capability objects.'''
480         typecapabilities = []
481         caps = self.get_value(self.CAPABILITIES, None, True)
482         if caps:
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,
488                                         self.custom_def)
489                 typecapabilities.append(cap)
490         return typecapabilities
491
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()}
496
497     @property
498     def requirements(self):
499         return self.get_value(self.REQUIREMENTS, None, True)
500
501     def get_all_requirements(self):
502         return self.requirements
503
504     @property
505     def interfaces(self):
506         return self.get_value(self.INTERFACES)
507
508     @property
509     def lifecycle_inputs(self):
510         '''Return inputs to life cycle operations if found.'''
511         inputs = []
512         interfaces = self.interfaces
513         if interfaces:
514             for name, value in interfaces.items():
515                 if name == ifaces.LIFECYCLE:
516                     for x, y in value.items():
517                         if x == 'inputs':
518                             for i in y.iterkeys():
519                                 inputs.append(i)
520         return inputs
521
522     @property
523     def lifecycle_operations(self):
524         '''Return available life cycle operations if found.'''
525         ops = None
526         interfaces = self.interfaces
527         if interfaces:
528             i = InterfacesDef(self.type, ifaces.LIFECYCLE)
529             ops = i.lifecycle_ops
530         return ops
531
532     def get_capability(self, name):
533         caps = self.get_capabilities()
534         if caps and name in caps.keys():
535             return caps[name].value
536
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
541
542     def _validate_keys(self):
543         if self.defs:
544             for key in self.defs.keys():
545                 if key not in self.SECTIONS:
546                     ValidationIssueCollector.appendException(
547                         UnknownFieldError(what='Nodetype"%s"' % self.ntype,
548                                           field=key))
549 */