Fix StatefulEntityType when entitytype is not define
[parser.git] / tosca2heat / tosca-parser / toscaparser / dataentity.py
1 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
2 #    not use this file except in compliance with the License. You may obtain
3 #    a copy of the License at
4 #
5 #         http://www.apache.org/licenses/LICENSE-2.0
6 #
7 #    Unless required by applicable law or agreed to in writing, software
8 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 #    License for the specific language governing permissions and limitations
11 #    under the License.
12
13 from toscaparser.common.exception import ExceptionCollector
14 from toscaparser.common.exception import MissingRequiredFieldError
15 from toscaparser.common.exception import TypeMismatchError
16 from toscaparser.common.exception import UnknownFieldError
17 from toscaparser.elements.constraints import Schema
18 from toscaparser.elements.datatype import DataType
19 from toscaparser.elements.portspectype import PortSpec
20 from toscaparser.elements.scalarunit import ScalarUnit_Frequency
21 from toscaparser.elements.scalarunit import ScalarUnit_Size
22 from toscaparser.elements.scalarunit import ScalarUnit_Time
23 from toscaparser.utils.gettextutils import _
24 from toscaparser.utils import validateutils
25
26
27 class DataEntity(object):
28     '''A complex data value entity.'''
29
30     def __init__(self, datatypename, value_dict, custom_def=None,
31                  prop_name=None):
32         self.custom_def = custom_def
33         self.datatype = DataType(datatypename, custom_def)
34         self.schema = self.datatype.get_all_properties()
35         self.value = value_dict
36         self.property_name = prop_name
37
38     def validate(self):
39         '''Validate the value by the definition of the datatype.'''
40
41         # A datatype can not have both 'type' and 'properties' definitions.
42         # If the datatype has 'type' definition
43         if self.datatype.value_type:
44             self.value = DataEntity.validate_datatype(self.datatype.value_type,
45                                                       self.value,
46                                                       None,
47                                                       self.custom_def)
48             schema = Schema(self.property_name, self.datatype.defs)
49             for constraint in schema.constraints:
50                 constraint.validate(self.value)
51         # If the datatype has 'properties' definition
52         else:
53             if not isinstance(self.value, dict):
54                 ExceptionCollector.appendException(
55                     TypeMismatchError(what=self.value,
56                                       type=self.datatype.type))
57             allowed_props = []
58             required_props = []
59             default_props = {}
60             if self.schema:
61                 allowed_props = self.schema.keys()
62                 for name, prop_def in self.schema.items():
63                     if prop_def.required:
64                         required_props.append(name)
65                     if prop_def.default:
66                         default_props[name] = prop_def.default
67
68             # check allowed field
69             for value_key in list(self.value.keys()):
70                 if value_key not in allowed_props:
71                     ExceptionCollector.appendException(
72                         UnknownFieldError(what=(_('Data value of type "%s"')
73                                                 % self.datatype.type),
74                                           field=value_key))
75
76             # check default field
77             for def_key, def_value in list(default_props.items()):
78                 if def_key not in list(self.value.keys()):
79                     self.value[def_key] = def_value
80
81             # check missing field
82             missingprop = []
83             for req_key in required_props:
84                 if req_key not in list(self.value.keys()):
85                     missingprop.append(req_key)
86             if missingprop:
87                 ExceptionCollector.appendException(
88                     MissingRequiredFieldError(
89                         what=(_('Data value of type "%s"')
90                               % self.datatype.type), required=missingprop))
91
92             # check every field
93             for name, value in list(self.value.items()):
94                 schema_name = self._find_schema(name)
95                 if not schema_name:
96                     continue
97                 prop_schema = Schema(name, schema_name)
98                 # check if field value meets type defined
99                 DataEntity.validate_datatype(prop_schema.type, value,
100                                              prop_schema.entry_schema,
101                                              self.custom_def)
102                 # check if field value meets constraints defined
103                 if prop_schema.constraints:
104                     for constraint in prop_schema.constraints:
105                         if isinstance(value, list):
106                             for val in value:
107                                 constraint.validate(val)
108                         else:
109                             constraint.validate(value)
110
111         return self.value
112
113     def _find_schema(self, name):
114         if self.schema and name in self.schema.keys():
115             return self.schema[name].schema
116
117     @staticmethod
118     def validate_datatype(type, value, entry_schema=None, custom_def=None,
119                           prop_name=None):
120         '''Validate value with given type.
121
122         If type is list or map, validate its entry by entry_schema(if defined)
123         If type is a user-defined complex datatype, custom_def is required.
124         '''
125         from toscaparser.functions import is_function
126         if is_function(value):
127             return value
128         if type == Schema.STRING:
129             return validateutils.validate_string(value)
130         elif type == Schema.INTEGER:
131             return validateutils.validate_integer(value)
132         elif type == Schema.FLOAT:
133             return validateutils.validate_float(value)
134         elif type == Schema.NUMBER:
135             return validateutils.validate_numeric(value)
136         elif type == Schema.BOOLEAN:
137             return validateutils.validate_boolean(value)
138         elif type == Schema.RANGE:
139             return validateutils.validate_range(value)
140         elif type == Schema.TIMESTAMP:
141             validateutils.validate_timestamp(value)
142             return value
143         elif type == Schema.LIST:
144             validateutils.validate_list(value)
145             if entry_schema:
146                 DataEntity.validate_entry(value, entry_schema, custom_def)
147             return value
148         elif type == Schema.SCALAR_UNIT_SIZE:
149             return ScalarUnit_Size(value).validate_scalar_unit()
150         elif type == Schema.SCALAR_UNIT_FREQUENCY:
151             return ScalarUnit_Frequency(value).validate_scalar_unit()
152         elif type == Schema.SCALAR_UNIT_TIME:
153             return ScalarUnit_Time(value).validate_scalar_unit()
154         elif type == Schema.VERSION:
155             return validateutils.TOSCAVersionProperty(value).get_version()
156         elif type == Schema.MAP:
157             validateutils.validate_map(value)
158             if entry_schema:
159                 DataEntity.validate_entry(value, entry_schema, custom_def)
160             return value
161         elif type == Schema.PORTSPEC:
162             # TODO(TBD) bug 1567063, validate source & target as PortDef type
163             # as complex types not just as integers
164             PortSpec.validate_additional_req(value, prop_name, custom_def)
165         else:
166             data = DataEntity(type, value, custom_def)
167             return data.validate()
168
169     @staticmethod
170     def validate_entry(value, entry_schema, custom_def=None):
171         '''Validate entries for map and list.'''
172         schema = Schema(None, entry_schema)
173         valuelist = value
174         if isinstance(value, dict):
175             valuelist = list(value.values())
176         for v in valuelist:
177             DataEntity.validate_datatype(schema.type, v, schema.entry_schema,
178                                          custom_def)
179             if schema.constraints:
180                 for constraint in schema.constraints:
181                     constraint.validate(v)
182         return value