Fix checkstyle violations in sdc/jtosca
[sdc/sdc-tosca.git] / src / main / java / org / onap / sdc / toscaparser / api / EntityTemplate.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;
22
23 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
24 import org.onap.sdc.toscaparser.api.elements.*;
25 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
26
27
28 import javax.annotation.Nullable;
29 import java.util.ArrayList;
30 import java.util.LinkedHashMap;
31 import java.util.Map;
32
33 public abstract class EntityTemplate {
34     // Base class for TOSCA templates
35
36     protected static final String DERIVED_FROM = "derived_from";
37     protected static final String PROPERTIES = "properties";
38     protected static final String REQUIREMENTS = "requirements";
39     protected static final String INTERFACES = "interfaces";
40     protected static final String CAPABILITIES = "capabilities";
41     protected static final String TYPE = "type";
42     protected static final String DESCRIPTION = "description";
43     protected static final String DIRECTIVES = "directives";
44     protected static final String ATTRIBUTES = "attributes";
45     protected static final String ARTIFACTS = "artifacts";
46     protected static final String NODE_FILTER = "node_filter";
47     protected static final String COPY = "copy";
48
49     protected static final String SECTIONS[] = {
50             DERIVED_FROM, PROPERTIES, REQUIREMENTS, INTERFACES,
51             CAPABILITIES, TYPE, DESCRIPTION, DIRECTIVES,
52             ATTRIBUTES, ARTIFACTS, NODE_FILTER, COPY};
53
54     private static final String NODE = "node";
55     private static final String CAPABILITY = "capability";
56     private static final String RELATIONSHIP = "relationship";
57     private static final String OCCURRENCES = "occurrences";
58
59     protected static final String REQUIREMENTS_SECTION[] = {
60             NODE, CAPABILITY, RELATIONSHIP, OCCURRENCES, NODE_FILTER};
61
62     //# Special key names
63     private static final String METADATA = "metadata";
64     protected static final String SPECIAL_SECTIONS[] = {METADATA};
65
66     protected String name;
67     protected LinkedHashMap<String, Object> entityTpl;
68     protected LinkedHashMap<String, Object> customDef;
69     protected StatefulEntityType typeDefinition;
70     private ArrayList<Property> _properties;
71     private ArrayList<InterfacesDef> _interfaces;
72     private ArrayList<RequirementAssignment> _requirements;
73     private ArrayList<CapabilityAssignment> _capabilities;
74
75     @Nullable
76     private NodeTemplate _parentNodeTemplate;
77
78     // dummy constructor for subclasses that don't want super
79     public EntityTemplate() {
80         return;
81     }
82
83     public EntityTemplate(String _name,
84                           LinkedHashMap<String, Object> _template,
85                           String _entityName,
86                           LinkedHashMap<String, Object> _customDef) {
87         this(_name, _template, _entityName, _customDef, null);
88     }
89
90     @SuppressWarnings("unchecked")
91     public EntityTemplate(String _name,
92                           LinkedHashMap<String, Object> _template,
93                           String _entityName,
94                           LinkedHashMap<String, Object> _customDef,
95                           NodeTemplate parentNodeTemplate) {
96         name = _name;
97         entityTpl = _template;
98         customDef = _customDef;
99         _validateField(entityTpl);
100         String type = (String) entityTpl.get("type");
101         UnsupportedType.validateType(type);
102         if (_entityName.equals("node_type")) {
103             if (type != null) {
104                 typeDefinition = new NodeType(type, customDef);
105             } else {
106                 typeDefinition = null;
107             }
108         }
109         if (_entityName.equals("relationship_type")) {
110             Object relationship = _template.get("relationship");
111             type = null;
112             if (relationship != null && relationship instanceof LinkedHashMap) {
113                 type = (String) ((LinkedHashMap<String, Object>) relationship).get("type");
114             } else if (relationship instanceof String) {
115                 type = (String) entityTpl.get("relationship");
116             } else {
117                 type = (String) entityTpl.get("type");
118             }
119             UnsupportedType.validateType(type);
120             typeDefinition = new RelationshipType(type, null, customDef);
121         }
122         if (_entityName.equals("policy_type")) {
123             if (type == null) {
124                 //msg = (_('Policy definition of "%(pname)s" must have'
125                 //       ' a "type" ''attribute.') % dict(pname=name))
126                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE140", String.format(
127                         "ValidationError: Policy definition of \"%s\" must have a \"type\" attribute", name)));
128             }
129             typeDefinition = new PolicyType(type, customDef);
130         }
131         if (_entityName.equals("group_type")) {
132             if (type != null) {
133                 typeDefinition = new GroupType(type, customDef);
134             } else {
135                 typeDefinition = null;
136             }
137         }
138         _properties = null;
139         _interfaces = null;
140         _requirements = null;
141         _capabilities = null;
142         _parentNodeTemplate = parentNodeTemplate;
143     }
144
145     public NodeTemplate getParentNodeTemplate() {
146         return _parentNodeTemplate;
147     }
148
149     public String getType() {
150         if (typeDefinition != null) {
151             String clType = typeDefinition.getClass().getSimpleName();
152             if (clType.equals("NodeType")) {
153                 return (String) ((NodeType) typeDefinition).getType();
154             } else if (clType.equals("PolicyType")) {
155                 return (String) ((PolicyType) typeDefinition).getType();
156             } else if (clType.equals("GroupType")) {
157                 return (String) ((GroupType) typeDefinition).getType();
158             } else if (clType.equals("RelationshipType")) {
159                 return (String) ((RelationshipType) typeDefinition).getType();
160             }
161         }
162         return null;
163     }
164
165     public Object getParentType() {
166         if (typeDefinition != null) {
167             String clType = typeDefinition.getClass().getSimpleName();
168             if (clType.equals("NodeType")) {
169                 return ((NodeType) typeDefinition).getParentType();
170             } else if (clType.equals("PolicyType")) {
171                 return ((PolicyType) typeDefinition).getParentType();
172             } else if (clType.equals("GroupType")) {
173                 return ((GroupType) typeDefinition).getParentType();
174             } else if (clType.equals("RelationshipType")) {
175                 return ((RelationshipType) typeDefinition).getParentType();
176             }
177         }
178         return null;
179     }
180
181     @SuppressWarnings("unchecked")
182     public RequirementAssignments getRequirements() {
183         if (_requirements == null) {
184             _requirements = _createRequirements();
185         }
186         return new RequirementAssignments(_requirements);
187     }
188
189     private ArrayList<RequirementAssignment> _createRequirements() {
190         ArrayList<RequirementAssignment> reqs = new ArrayList<>();
191         ArrayList<Map<String, Object>> requirements = (ArrayList<Map<String, Object>>)
192                 typeDefinition.getValue(REQUIREMENTS, entityTpl, false);
193         if (requirements == null) {
194             requirements = new ArrayList<>();
195         }
196         for (Map<String, Object> req : requirements) {
197             for (String reqName : req.keySet()) {
198                 Object reqItem = req.get(reqName);
199                 if (reqItem instanceof LinkedHashMap) {
200                     Object rel = ((LinkedHashMap<String, Object>) reqItem).get("relationship");
201 //                                      LinkedHashMap relationship = rel instanceof LinkedHashMap ? (LinkedHashMap) rel : null;
202                     String nodeName = ((LinkedHashMap<String, Object>) reqItem).get("node").toString();
203                     Object capability = ((LinkedHashMap<String, Object>) reqItem).get("capability");
204                     String capabilityString = capability != null ? capability.toString() : null;
205
206                     reqs.add(new RequirementAssignment(reqName, nodeName, capabilityString, rel));
207                 } else if (reqItem instanceof String) { //short notation
208                     String nodeName = String.valueOf(reqItem);
209                     reqs.add(new RequirementAssignment(reqName, nodeName));
210                 }
211             }
212         }
213         return reqs;
214     }
215
216     public ArrayList<Property> getPropertiesObjects() {
217         // Return properties objects for this template
218         if (_properties == null) {
219             _properties = _createProperties();
220         }
221         return _properties;
222     }
223
224     public LinkedHashMap<String, Property> getProperties() {
225         LinkedHashMap<String, Property> props = new LinkedHashMap<>();
226         for (Property po : getPropertiesObjects()) {
227             props.put(po.getName(), po);
228         }
229         return props;
230     }
231
232     public Object getPropertyValue(String name) {
233         LinkedHashMap<String, Property> props = getProperties();
234         Property p = props.get(name);
235         return p != null ? p.getValue() : null;
236     }
237
238     public String getPropertyType(String name) {
239         Property property = getProperties().get(name);
240         if (property != null) {
241             return property.getType();
242         }
243         return null;
244     }
245
246     public ArrayList<InterfacesDef> getInterfaces() {
247         if (_interfaces == null) {
248             _interfaces = _createInterfaces();
249         }
250         return _interfaces;
251     }
252
253     public ArrayList<CapabilityAssignment> getCapabilitiesObjects() {
254         // Return capabilities objects for this template
255         if (_capabilities == null) {
256             _capabilities = _createCapabilities();
257         }
258         return _capabilities;
259
260     }
261
262     public CapabilityAssignments getCapabilities() {
263         LinkedHashMap<String, CapabilityAssignment> caps = new LinkedHashMap<String, CapabilityAssignment>();
264         for (CapabilityAssignment cap : getCapabilitiesObjects()) {
265             caps.put(cap.getName(), cap);
266         }
267         return new CapabilityAssignments(caps);
268     }
269
270     public boolean isDerivedFrom(String typeStr) {
271         // Returns true if this object is derived from 'type_str'.
272         // False otherwise
273
274         if (getType() == null) {
275             return false;
276         } else if (getType().equals(typeStr)) {
277             return true;
278         } else if (getParentType() != null) {
279             return ((EntityType) getParentType()).isDerivedFrom(typeStr);
280         }
281         return false;
282     }
283
284     @SuppressWarnings("unchecked")
285     private ArrayList<CapabilityAssignment> _createCapabilities() {
286         ArrayList<CapabilityAssignment> capability = new ArrayList<CapabilityAssignment>();
287         LinkedHashMap<String, Object> caps = (LinkedHashMap<String, Object>)
288                 ((EntityType) typeDefinition).getValue(CAPABILITIES, entityTpl, true);
289         if (caps != null) {
290             //?!? getCapabilities defined only for NodeType...
291             LinkedHashMap<String, CapabilityTypeDef> capabilities = null;
292             if (typeDefinition instanceof NodeType) {
293                 capabilities = ((NodeType) typeDefinition).getCapabilities();
294             } else if (typeDefinition instanceof GroupType) {
295                 capabilities = ((GroupType) typeDefinition).getCapabilities();
296             }
297             for (Map.Entry<String, Object> me : caps.entrySet()) {
298                 String name = me.getKey();
299                 LinkedHashMap<String, Object> props = (LinkedHashMap<String, Object>) me.getValue();
300                 if (capabilities.get(name) != null) {
301                     CapabilityTypeDef c = capabilities.get(name);  // a CapabilityTypeDef
302                     LinkedHashMap<String, Object> properties = new LinkedHashMap<String, Object>();
303                     // first use the definition default value
304                     LinkedHashMap<String, Object> cprops = c.getProperties();
305                     if (cprops != null) {
306                         for (Map.Entry<String, Object> cpe : cprops.entrySet()) {
307                             String propertyName = cpe.getKey();
308                             LinkedHashMap<String, Object> propertyDef = (LinkedHashMap<String, Object>) cpe.getValue();
309                             Object dob = propertyDef.get("default");
310                             if (dob != null) {
311                                 properties.put(propertyName, dob);
312
313                             }
314                         }
315                     }
316                     // then update (if available) with the node properties
317                     LinkedHashMap<String, Object> pp = (LinkedHashMap<String, Object>) props.get("properties");
318                     if (pp != null) {
319                         properties.putAll(pp);
320                     }
321                     CapabilityAssignment cap = new CapabilityAssignment(name, properties, c, customDef);
322                     capability.add(cap);
323                 }
324             }
325         }
326         return capability;
327     }
328
329     protected void _validateProperties(LinkedHashMap<String, Object> template, StatefulEntityType entityType) {
330         @SuppressWarnings("unchecked")
331         LinkedHashMap<String, Object> properties = (LinkedHashMap<String, Object>) entityType.getValue(PROPERTIES, template, false);
332         _commonValidateProperties(entityType, properties);
333     }
334
335     protected void _validateCapabilities() {
336         //BUG??? getCapabilities only defined in NodeType...
337         LinkedHashMap<String, CapabilityTypeDef> typeCapabilities = ((NodeType) typeDefinition).getCapabilities();
338         ArrayList<String> allowedCaps = new ArrayList<String>();
339         if (typeCapabilities != null) {
340             allowedCaps.addAll(typeCapabilities.keySet());
341         }
342         @SuppressWarnings("unchecked")
343         LinkedHashMap<String, Object> capabilities = (LinkedHashMap<String, Object>)
344                 ((EntityType) typeDefinition).getValue(CAPABILITIES, entityTpl, false);
345         if (capabilities != null) {
346             _commonValidateField(capabilities, allowedCaps, "capabilities");
347             _validateCapabilitiesProperties(capabilities);
348         }
349     }
350
351     @SuppressWarnings("unchecked")
352     private void _validateCapabilitiesProperties(LinkedHashMap<String, Object> capabilities) {
353         for (Map.Entry<String, Object> me : capabilities.entrySet()) {
354             String cap = me.getKey();
355             LinkedHashMap<String, Object> props = (LinkedHashMap<String, Object>) me.getValue();
356             CapabilityAssignment capability = getCapability(cap);
357             if (capability == null) {
358                 continue;
359             }
360             CapabilityTypeDef capabilitydef = capability.getDefinition();
361             _commonValidateProperties(capabilitydef, (LinkedHashMap<String, Object>) props.get(PROPERTIES));
362
363             // validating capability properties values
364             for (Property prop : getCapability(cap).getPropertiesObjects()) {
365                 prop.validate();
366
367                 if (cap.equals("scalable") && prop.getName().equals("default_instances")) {
368                     LinkedHashMap<String, Object> propDict = (LinkedHashMap<String, Object>) props.get(PROPERTIES);
369                     int minInstances = (int) propDict.get("min_instances");
370                     int maxInstances = (int) propDict.get("max_instances");
371                     int defaultInstances = (int) propDict.get("default_instances");
372                     if (defaultInstances < minInstances || defaultInstances > maxInstances) {
373                         //err_msg = ('"properties" of template "%s": '
374                         //           '"default_instances" value is not between '
375                         //           '"min_instances" and "max_instances".' %
376                         //           self.name)
377                         ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE141", String.format(
378                                 "ValidationError: \"properties\" of template \"%s\": \"default_instances\" value is not between \"min_instances\" and \"max_instances\"",
379                                 name)));
380                     }
381                 }
382             }
383         }
384     }
385
386     private void _commonValidateProperties(StatefulEntityType entityType, LinkedHashMap<String, Object> properties) {
387         ArrayList<String> allowedProps = new ArrayList<String>();
388         ArrayList<String> requiredProps = new ArrayList<String>();
389         for (PropertyDef p : entityType.getPropertiesDefObjects()) {
390             allowedProps.add(p.getName());
391             // If property is 'required' and has no 'default' value then record
392             if (p.isRequired() && p.getDefault() == null) {
393                 requiredProps.add(p.getName());
394             }
395         }
396         // validate all required properties have values
397         if (properties != null) {
398             ArrayList<String> reqPropsNoValueOrDefault = new ArrayList<String>();
399             _commonValidateField(properties, allowedProps, "properties");
400             // make sure it's not missing any property required by a tosca type
401             for (String r : requiredProps) {
402                 if (properties.get(r) == null) {
403                     reqPropsNoValueOrDefault.add(r);
404                 }
405             }
406             // Required properties found without value or a default value
407             if (!reqPropsNoValueOrDefault.isEmpty()) {
408                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE003", String.format(
409                         "MissingRequiredFieldError: properties of template \"%s\" are missing field(s): %s",
410                         name, reqPropsNoValueOrDefault.toString())));
411             }
412         } else {
413             // Required properties in schema, but not in template
414             if (!requiredProps.isEmpty()) {
415                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE004", String.format(
416                         "MissingRequiredFieldError2: properties of template \"%s\" are missing field(s): %s",
417                         name, requiredProps.toString())));
418             }
419         }
420     }
421
422     @SuppressWarnings("unchecked")
423     private void _validateField(LinkedHashMap<String, Object> template) {
424         if (!(template instanceof LinkedHashMap)) {
425             ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE142", String.format(
426                     "MissingRequiredFieldError: Template \"%s\" is missing required field \"%s\"", name, TYPE)));
427             return;//???
428         }
429         boolean bBad = false;
430         Object relationship = ((LinkedHashMap<String, Object>) template).get("relationship");
431         if (relationship != null) {
432             if (!(relationship instanceof String)) {
433                 bBad = (((LinkedHashMap<String, Object>) relationship).get(TYPE) == null);
434             } else if (relationship instanceof String) {
435                 bBad = (template.get("relationship") == null);
436             }
437         } else {
438             bBad = (template.get(TYPE) == null);
439         }
440         if (bBad) {
441             ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE143", String.format(
442                     "MissingRequiredFieldError: Template \"%s\" is missing required field \"%s\"", name, TYPE)));
443         }
444     }
445
446     protected void _commonValidateField(LinkedHashMap<String, Object> schema, ArrayList<String> allowedList, String section) {
447         for (String sname : schema.keySet()) {
448             boolean bFound = false;
449             for (String allowed : allowedList) {
450                 if (sname.equals(allowed)) {
451                     bFound = true;
452                     break;
453                 }
454             }
455             if (!bFound) {
456                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE144", String.format(
457                         "UnknownFieldError: Section \"%s\" of template \"%s\" contains unknown field \"%s\"", section, name, sname)));
458             }
459         }
460
461     }
462
463     @SuppressWarnings("unchecked")
464     private ArrayList<Property> _createProperties() {
465         ArrayList<Property> props = new ArrayList<Property>();
466         LinkedHashMap<String, Object> properties = (LinkedHashMap<String, Object>)
467                 ((EntityType) typeDefinition).getValue(PROPERTIES, entityTpl, false);
468         if (properties == null) {
469             properties = new LinkedHashMap<String, Object>();
470         }
471         for (Map.Entry<String, Object> me : properties.entrySet()) {
472             String pname = me.getKey();
473             Object pvalue = me.getValue();
474             LinkedHashMap<String, PropertyDef> propsDef = ((StatefulEntityType) typeDefinition).getPropertiesDef();
475             if (propsDef != null && propsDef.get(pname) != null) {
476                 PropertyDef pd = (PropertyDef) propsDef.get(pname);
477                 Property prop = new Property(pname, pvalue, pd.getSchema(), customDef);
478                 props.add(prop);
479             }
480         }
481         ArrayList<PropertyDef> pds = ((StatefulEntityType) typeDefinition).getPropertiesDefObjects();
482         for (Object pdo : pds) {
483             PropertyDef pd = (PropertyDef) pdo;
484             if (pd.getDefault() != null && properties.get(pd.getName()) == null) {
485                 Property prop = new Property(pd.getName(), pd.getDefault(), pd.getSchema(), customDef);
486                 props.add(prop);
487             }
488         }
489         return props;
490     }
491
492     @SuppressWarnings("unchecked")
493     private ArrayList<InterfacesDef> _createInterfaces() {
494         ArrayList<InterfacesDef> interfaces = new ArrayList<>();
495         LinkedHashMap<String, Object> typeInterfaces = new LinkedHashMap<String, Object>();
496         if (typeDefinition instanceof RelationshipType) {
497             if (entityTpl instanceof LinkedHashMap) {
498                 typeInterfaces = (LinkedHashMap<String, Object>) entityTpl.get(INTERFACES);
499                 if (typeInterfaces == null) {
500                     for (String relName : entityTpl.keySet()) {
501                         Object relValue = entityTpl.get(relName);
502                         if (!relName.equals("type")) {
503                             Object relDef = relValue;
504                             LinkedHashMap<String, Object> rel = null;
505                             if (relDef instanceof LinkedHashMap) {
506                                 Object relob = ((LinkedHashMap<String, Object>) relDef).get("relationship");
507                                 if (relob instanceof LinkedHashMap) {
508                                     rel = (LinkedHashMap<String, Object>) relob;
509                                 }
510                             }
511                             if (rel != null) {
512                                 if (rel.get(INTERFACES) != null) {
513                                     typeInterfaces = (LinkedHashMap<String, Object>) rel.get(INTERFACES);
514                                     break;
515                                 }
516                             }
517                         }
518                     }
519                 }
520             }
521         } else {
522             typeInterfaces = (LinkedHashMap<String, Object>)
523                     ((EntityType) typeDefinition).getValue(INTERFACES, entityTpl, false);
524         }
525         if (typeInterfaces != null) {
526             for (Map.Entry<String, Object> me : typeInterfaces.entrySet()) {
527                 String interfaceType = me.getKey();
528                 LinkedHashMap<String, Object> value = (LinkedHashMap<String, Object>) me.getValue();
529                 for (Map.Entry<String, Object> ve : value.entrySet()) {
530                     String op = ve.getKey();
531                     Object opDef = ve.getValue();
532                     InterfacesDef iface = new InterfacesDef((EntityType) typeDefinition,
533                             interfaceType,
534                             this,
535                             op,
536                             opDef);
537                     interfaces.add(iface);
538                 }
539
540             }
541         }
542         return interfaces;
543     }
544
545     public CapabilityAssignment getCapability(String name) {
546         // Provide named capability
547         // :param name: name of capability
548         // :return: capability object if found, None otherwise
549         return getCapabilities().getCapabilityByName(name);
550     }
551
552     // getter
553     public String getName() {
554         return name;
555     }
556
557     public StatefulEntityType getTypeDefinition() {
558         return typeDefinition;
559     }
560
561     public LinkedHashMap<String, Object> getCustomDef() {
562         return customDef;
563     }
564
565     @Override
566     public String toString() {
567         return "EntityTemplate{" +
568                 "name='" + name + '\'' +
569                 ", entityTpl=" + entityTpl +
570                 ", customDef=" + customDef +
571                 ", typeDefinition=" + typeDefinition +
572                 ", _properties=" + _properties +
573                 ", _interfaces=" + _interfaces +
574                 ", _requirements=" + _requirements +
575                 ", _capabilities=" + _capabilities +
576                 '}';
577     }
578 }
579
580 /*python
581
582 class EntityTemplate(object):
583     '''Base class for TOSCA templates.'''
584
585     SECTIONS = (DERIVED_FROM, PROPERTIES, REQUIREMENTS,
586                 INTERFACES, CAPABILITIES, TYPE, DESCRIPTION, DIRECTIVES,
587                 ATTRIBUTES, ARTIFACTS, NODE_FILTER, COPY) = \
588                ('derived_from', 'properties', 'requirements', 'interfaces',
589                 'capabilities', 'type', 'description', 'directives',
590                 'attributes', 'artifacts', 'node_filter', 'copy')
591     REQUIREMENTS_SECTION = (NODE, CAPABILITY, RELATIONSHIP, OCCURRENCES, NODE_FILTER) = \
592                            ('node', 'capability', 'relationship',
593                             'occurrences', 'node_filter')
594     # Special key names
595     SPECIAL_SECTIONS = (METADATA) = ('metadata')
596
597     def __init__(self, name, template, entity_name, custom_def=None):
598         self.name = name
599         self.entity_tpl = template
600         self.custom_def = custom_def
601         self._validate_field(self.entity_tpl)
602         type = self.entity_tpl.get('type')
603         UnsupportedType.validate_type(type)
604         if entity_name == 'node_type':
605             self.type_definition = NodeType(type, custom_def) \
606                 if type is not None else None
607         if entity_name == 'relationship_type':
608             relationship = template.get('relationship')
609             type = None
610             if relationship and isinstance(relationship, dict):
611                 type = relationship.get('type')
612             elif isinstance(relationship, str):
613                 type = self.entity_tpl['relationship']
614             else:
615                 type = self.entity_tpl['type']
616             UnsupportedType.validate_type(type)
617             self.type_definition = RelationshipType(type,
618                                                     None, custom_def)
619         if entity_name == 'policy_type':
620             if not type:
621                 msg = (_('Policy definition of "%(pname)s" must have'
622                        ' a "type" ''attribute.') % dict(pname=name))
623                 ValidationIssueCollector.appendException(
624                     ValidationError(msg))
625
626             self.type_definition = PolicyType(type, custom_def)
627         if entity_name == 'group_type':
628             self.type_definition = GroupType(type, custom_def) \
629                 if type is not None else None
630         self._properties = None
631         self._interfaces = None
632         self._requirements = None
633         self._capabilities = None
634
635     @property
636     def type(self):
637         if self.type_definition:
638             return self.type_definition.type
639
640     @property
641     def parent_type(self):
642         if self.type_definition:
643             return self.type_definition.parent_type
644
645     @property
646     def requirements(self):
647         if self._requirements is None:
648             self._requirements = self.type_definition.get_value(
649                 self.REQUIREMENTS,
650                 self.entity_tpl) or []
651         return self._requirements
652
653     def get_properties_objects(self):
654         '''Return properties objects for this template.'''
655         if self._properties is None:
656             self._properties = self._create_properties()
657         return self._properties
658
659     def get_properties(self):
660         '''Return a dictionary of property name-object pairs.'''
661         return {prop.name: prop
662                 for prop in self.get_properties_objects()}
663
664     def get_property_value(self, name):
665         '''Return the value of a given property name.'''
666         props = self.get_properties()
667         if props and name in props.keys():
668             return props[name].value
669
670     @property
671     def interfaces(self):
672         if self._interfaces is None:
673             self._interfaces = self._create_interfaces()
674         return self._interfaces
675
676     def get_capabilities_objects(self):
677         '''Return capabilities objects for this template.'''
678         if not self._capabilities:
679             self._capabilities = self._create_capabilities()
680         return self._capabilities
681
682     def get_capabilities(self):
683         '''Return a dictionary of capability name-object pairs.'''
684         return {cap.name: cap
685                 for cap in self.get_capabilities_objects()}
686
687     def is_derived_from(self, type_str):
688         '''Check if object inherits from the given type.
689
690         Returns true if this object is derived from 'type_str'.
691         False otherwise.
692         '''
693         if not self.type:
694             return False
695         elif self.type == type_str:
696             return True
697         elif self.parent_type:
698             return self.parent_type.is_derived_from(type_str)
699         else:
700             return False
701
702     def _create_capabilities(self):
703         capability = []
704         caps = self.type_definition.get_value(self.CAPABILITIES,
705                                               self.entity_tpl, True)
706         if caps:
707             for name, props in caps.items():
708                 capabilities = self.type_definition.get_capabilities()
709                 if name in capabilities.keys():
710                     c = capabilities[name]
711                     properties = {}
712                     # first use the definition default value
713                     if c.properties:
714                         for property_name in c.properties.keys():
715                             prop_def = c.properties[property_name]
716                             if 'default' in prop_def:
717                                 properties[property_name] = prop_def['default']
718                     # then update (if available) with the node properties
719                     if 'properties' in props and props['properties']:
720                         properties.update(props['properties'])
721
722                     cap = CapabilityAssignment(name, properties, c)
723                     capability.append(cap)
724         return capability
725
726     def _validate_properties(self, template, entitytype):
727         properties = entitytype.get_value(self.PROPERTIES, template)
728         self._common_validate_properties(entitytype, properties)
729
730     def _validate_capabilities(self):
731         type_capabilities = self.type_definition.get_capabilities()
732         allowed_caps = \
733             type_capabilities.keys() if type_capabilities else []
734         capabilities = self.type_definition.get_value(self.CAPABILITIES,
735                                                       self.entity_tpl)
736         if capabilities:
737             self._common_validate_field(capabilities, allowed_caps,
738                                         'capabilities')
739             self._validate_capabilities_properties(capabilities)
740
741     def _validate_capabilities_properties(self, capabilities):
742         for cap, props in capabilities.items():
743             capability = self.get_capability(cap)
744             if not capability:
745                 continue
746             capabilitydef = capability.definition
747             self._common_validate_properties(capabilitydef,
748                                              props[self.PROPERTIES])
749
750             # validating capability properties values
751             for prop in self.get_capability(cap).get_properties_objects():
752                 prop.validate()
753
754                 # tODO(srinivas_tadepalli): temporary work around to validate
755                 # default_instances until standardized in specification
756                 if cap == "scalable" and prop.name == "default_instances":
757                     prop_dict = props[self.PROPERTIES]
758                     min_instances = prop_dict.get("min_instances")
759                     max_instances = prop_dict.get("max_instances")
760                     default_instances = prop_dict.get("default_instances")
761                     if not (min_instances <= default_instances
762                             <= max_instances):
763                         err_msg = ('"properties" of template "%s": '
764                                    '"default_instances" value is not between '
765                                    '"min_instances" and "max_instances".' %
766                                    self.name)
767                         ValidationIssueCollector.appendException(
768                             ValidationError(message=err_msg))
769
770     def _common_validate_properties(self, entitytype, properties):
771         allowed_props = []
772         required_props = []
773         for p in entitytype.get_properties_def_objects():
774             allowed_props.append(p.name)
775             # If property is 'required' and has no 'default' value then record
776             if p.required and p.default is None:
777                 required_props.append(p.name)
778         # validate all required properties have values
779         if properties:
780             req_props_no_value_or_default = []
781             self._common_validate_field(properties, allowed_props,
782                                         'properties')
783             # make sure it's not missing any property required by a tosca type
784             for r in required_props:
785                 if r not in properties.keys():
786                     req_props_no_value_or_default.append(r)
787             # Required properties found without value or a default value
788             if req_props_no_value_or_default:
789                 ValidationIssueCollector.appendException(
790                     MissingRequiredFieldError(
791                         what='"properties" of template "%s"' % self.name,
792                         required=req_props_no_value_or_default))
793         else:
794             # Required properties in schema, but not in template
795             if required_props:
796                 ValidationIssueCollector.appendException(
797                     MissingRequiredFieldError(
798                         what='"properties" of template "%s"' % self.name,
799                         required=required_props))
800
801     def _validate_field(self, template):
802         if not isinstance(template, dict):
803             ValidationIssueCollector.appendException(
804                 MissingRequiredFieldError(
805                     what='Template "%s"' % self.name, required=self.TYPE))
806         try:
807             relationship = template.get('relationship')
808             if relationship and not isinstance(relationship, str):
809                 relationship[self.TYPE]
810             elif isinstance(relationship, str):
811                 template['relationship']
812             else:
813                 template[self.TYPE]
814         except KeyError:
815             ValidationIssueCollector.appendException(
816                 MissingRequiredFieldError(
817                     what='Template "%s"' % self.name, required=self.TYPE))
818
819     def _common_validate_field(self, schema, allowedlist, section):
820         for name in schema:
821             if name not in allowedlist:
822                 ValidationIssueCollector.appendException(
823                     UnknownFieldError(
824                         what=('"%(section)s" of template "%(nodename)s"'
825                               % {'section': section, 'nodename': self.name}),
826                         field=name))
827
828     def _create_properties(self):
829         props = []
830         properties = self.type_definition.get_value(self.PROPERTIES,
831                                                     self.entity_tpl) or {}
832         for name, value in properties.items():
833             props_def = self.type_definition.get_properties_def()
834             if props_def and name in props_def:
835                 prop = Property(name, value,
836                                 props_def[name].schema, self.custom_def)
837                 props.append(prop)
838         for p in self.type_definition.get_properties_def_objects():
839             if p.default is not None and p.name not in properties.keys():
840                 prop = Property(p.name, p.default, p.schema, self.custom_def)
841                 props.append(prop)
842         return props
843
844     def _create_interfaces(self):
845         interfaces = []
846         type_interfaces = None
847         if isinstance(self.type_definition, RelationshipType):
848             if isinstance(self.entity_tpl, dict):
849                 if self.INTERFACES in self.entity_tpl:
850                     type_interfaces = self.entity_tpl[self.INTERFACES]
851                 else:
852                     for rel_def, value in self.entity_tpl.items():
853                         if rel_def != 'type':
854                             rel_def = self.entity_tpl.get(rel_def)
855                             rel = None
856                             if isinstance(rel_def, dict):
857                                 rel = rel_def.get('relationship')
858                             if rel:
859                                 if self.INTERFACES in rel:
860                                     type_interfaces = rel[self.INTERFACES]
861                                     break
862         else:
863             type_interfaces = self.type_definition.get_value(self.INTERFACES,
864                                                              self.entity_tpl)
865         if type_interfaces:
866             for interface_type, value in type_interfaces.items():
867                 for op, op_def in value.items():
868                     iface = InterfacesDef(self.type_definition,
869                                           interfacetype=interface_type,
870                                           node_template=self,
871                                           name=op,
872                                           value=op_def)
873                     interfaces.append(iface)
874         return interfaces
875
876     def get_capability(self, name):
877         """Provide named capability
878
879         :param name: name of capability
880         :return: capability object if found, None otherwise
881         """
882         caps = self.get_capabilities()
883         if caps and name in caps.keys():
884             return caps[name]
885 */