2014-12-18 11:06:29 +00:00
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
|
|
# not use this file except in compliance with the License. You may obtain
|
|
|
|
# a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
# License for the specific language governing permissions and limitations
|
|
|
|
# under the License.
|
|
|
|
|
2015-11-03 15:09:39 -08:00
|
|
|
from toscaparser.common.exception import ExceptionCollector
|
2015-08-25 08:16:57 -07:00
|
|
|
from toscaparser.common.exception import MissingRequiredFieldError
|
|
|
|
from toscaparser.common.exception import TypeMismatchError
|
|
|
|
from toscaparser.common.exception import UnknownFieldError
|
|
|
|
from toscaparser.elements.constraints import Schema
|
|
|
|
from toscaparser.elements.datatype import DataType
|
2016-03-28 23:00:20 -05:00
|
|
|
from toscaparser.elements.portspectype import PortSpec
|
2015-08-25 08:16:57 -07:00
|
|
|
from toscaparser.elements.scalarunit import ScalarUnit_Frequency
|
|
|
|
from toscaparser.elements.scalarunit import ScalarUnit_Size
|
|
|
|
from toscaparser.elements.scalarunit import ScalarUnit_Time
|
|
|
|
from toscaparser.utils.gettextutils import _
|
|
|
|
from toscaparser.utils import validateutils
|
2014-12-18 11:06:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
class DataEntity(object):
|
|
|
|
'''A complex data value entity.'''
|
|
|
|
|
2016-03-28 23:00:20 -05:00
|
|
|
def __init__(self, datatypename, value_dict, custom_def=None,
|
|
|
|
prop_name=None):
|
2014-12-18 11:06:29 +00:00
|
|
|
self.custom_def = custom_def
|
|
|
|
self.datatype = DataType(datatypename, custom_def)
|
2015-03-23 17:14:30 -07:00
|
|
|
self.schema = self.datatype.get_all_properties()
|
2014-12-18 11:06:29 +00:00
|
|
|
self.value = value_dict
|
2016-03-28 23:00:20 -05:00
|
|
|
self.property_name = prop_name
|
2014-12-18 11:06:29 +00:00
|
|
|
|
|
|
|
def validate(self):
|
|
|
|
'''Validate the value by the definition of the datatype.'''
|
|
|
|
|
2015-04-27 14:46:26 -04:00
|
|
|
# A datatype can not have both 'type' and 'properties' definitions.
|
|
|
|
# If the datatype has 'type' definition
|
2014-12-18 11:06:29 +00:00
|
|
|
if self.datatype.value_type:
|
2015-07-24 14:36:57 -07:00
|
|
|
self.value = DataEntity.validate_datatype(self.datatype.value_type,
|
|
|
|
self.value,
|
|
|
|
None,
|
|
|
|
self.custom_def)
|
2016-03-28 23:00:20 -05:00
|
|
|
schema = Schema(self.property_name, self.datatype.defs)
|
2014-12-18 11:06:29 +00:00
|
|
|
for constraint in schema.constraints:
|
|
|
|
constraint.validate(self.value)
|
|
|
|
# If the datatype has 'properties' definition
|
|
|
|
else:
|
|
|
|
if not isinstance(self.value, dict):
|
2015-11-03 15:09:39 -08:00
|
|
|
ExceptionCollector.appendException(
|
|
|
|
TypeMismatchError(what=self.value,
|
|
|
|
type=self.datatype.type))
|
2014-12-18 11:06:29 +00:00
|
|
|
allowed_props = []
|
|
|
|
required_props = []
|
|
|
|
default_props = {}
|
2015-03-23 17:14:30 -07:00
|
|
|
if self.schema:
|
|
|
|
allowed_props = self.schema.keys()
|
|
|
|
for name, prop_def in self.schema.items():
|
|
|
|
if prop_def.required:
|
|
|
|
required_props.append(name)
|
|
|
|
if prop_def.default:
|
|
|
|
default_props[name] = prop_def.default
|
2014-12-18 11:06:29 +00:00
|
|
|
|
|
|
|
# check allowed field
|
|
|
|
for value_key in list(self.value.keys()):
|
|
|
|
if value_key not in allowed_props:
|
2015-11-03 15:09:39 -08:00
|
|
|
ExceptionCollector.appendException(
|
2015-11-18 16:25:16 -08:00
|
|
|
UnknownFieldError(what=(_('Data value of type "%s"')
|
2015-11-03 15:09:39 -08:00
|
|
|
% self.datatype.type),
|
|
|
|
field=value_key))
|
2014-12-18 11:06:29 +00:00
|
|
|
|
|
|
|
# check default field
|
|
|
|
for def_key, def_value in list(default_props.items()):
|
|
|
|
if def_key not in list(self.value.keys()):
|
|
|
|
self.value[def_key] = def_value
|
|
|
|
|
|
|
|
# check missing field
|
|
|
|
missingprop = []
|
|
|
|
for req_key in required_props:
|
|
|
|
if req_key not in list(self.value.keys()):
|
|
|
|
missingprop.append(req_key)
|
|
|
|
if missingprop:
|
2015-11-03 15:09:39 -08:00
|
|
|
ExceptionCollector.appendException(
|
2015-11-18 16:25:16 -08:00
|
|
|
MissingRequiredFieldError(
|
|
|
|
what=(_('Data value of type "%s"')
|
|
|
|
% self.datatype.type), required=missingprop))
|
2014-12-18 11:06:29 +00:00
|
|
|
|
|
|
|
# check every field
|
|
|
|
for name, value in list(self.value.items()):
|
2016-04-22 09:20:18 +02:00
|
|
|
schema_name = self._find_schema(name)
|
|
|
|
if not schema_name:
|
|
|
|
continue
|
|
|
|
prop_schema = Schema(name, schema_name)
|
2014-12-18 11:06:29 +00:00
|
|
|
# check if field value meets type defined
|
|
|
|
DataEntity.validate_datatype(prop_schema.type, value,
|
|
|
|
prop_schema.entry_schema,
|
|
|
|
self.custom_def)
|
|
|
|
# check if field value meets constraints defined
|
|
|
|
if prop_schema.constraints:
|
|
|
|
for constraint in prop_schema.constraints:
|
2016-02-04 18:53:12 +05:30
|
|
|
if isinstance(value, list):
|
|
|
|
for val in value:
|
|
|
|
constraint.validate(val)
|
|
|
|
else:
|
|
|
|
constraint.validate(value)
|
2014-12-18 11:06:29 +00:00
|
|
|
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
def _find_schema(self, name):
|
2015-03-23 17:14:30 -07:00
|
|
|
if self.schema and name in self.schema.keys():
|
|
|
|
return self.schema[name].schema
|
2014-12-18 11:06:29 +00:00
|
|
|
|
|
|
|
@staticmethod
|
2016-03-28 23:00:20 -05:00
|
|
|
def validate_datatype(type, value, entry_schema=None, custom_def=None,
|
|
|
|
prop_name=None):
|
2014-12-18 11:06:29 +00:00
|
|
|
'''Validate value with given type.
|
|
|
|
|
|
|
|
If type is list or map, validate its entry by entry_schema(if defined)
|
|
|
|
If type is a user-defined complex datatype, custom_def is required.
|
|
|
|
'''
|
2016-05-18 10:29:01 +02:00
|
|
|
from toscaparser.functions import is_function
|
|
|
|
if is_function(value):
|
|
|
|
return value
|
2014-12-18 11:06:29 +00:00
|
|
|
if type == Schema.STRING:
|
2015-05-07 03:02:54 +08:00
|
|
|
return validateutils.validate_string(value)
|
2014-12-18 11:06:29 +00:00
|
|
|
elif type == Schema.INTEGER:
|
2015-05-07 03:02:54 +08:00
|
|
|
return validateutils.validate_integer(value)
|
2015-03-31 17:46:59 +05:30
|
|
|
elif type == Schema.FLOAT:
|
2015-05-07 03:02:54 +08:00
|
|
|
return validateutils.validate_float(value)
|
2014-12-18 11:06:29 +00:00
|
|
|
elif type == Schema.NUMBER:
|
2016-03-28 23:00:20 -05:00
|
|
|
return validateutils.validate_numeric(value)
|
2014-12-18 11:06:29 +00:00
|
|
|
elif type == Schema.BOOLEAN:
|
2015-05-07 03:02:54 +08:00
|
|
|
return validateutils.validate_boolean(value)
|
2016-02-04 18:53:12 +05:30
|
|
|
elif type == Schema.RANGE:
|
|
|
|
return validateutils.validate_range(value)
|
2015-03-31 17:46:59 +05:30
|
|
|
elif type == Schema.TIMESTAMP:
|
2015-08-12 10:55:06 +05:30
|
|
|
validateutils.validate_timestamp(value)
|
|
|
|
return value
|
2014-12-18 11:06:29 +00:00
|
|
|
elif type == Schema.LIST:
|
2015-05-07 03:02:54 +08:00
|
|
|
validateutils.validate_list(value)
|
2014-12-18 11:06:29 +00:00
|
|
|
if entry_schema:
|
|
|
|
DataEntity.validate_entry(value, entry_schema, custom_def)
|
|
|
|
return value
|
2015-01-27 01:36:16 +00:00
|
|
|
elif type == Schema.SCALAR_UNIT_SIZE:
|
2015-05-07 03:02:54 +08:00
|
|
|
return ScalarUnit_Size(value).validate_scalar_unit()
|
|
|
|
elif type == Schema.SCALAR_UNIT_FREQUENCY:
|
|
|
|
return ScalarUnit_Frequency(value).validate_scalar_unit()
|
|
|
|
elif type == Schema.SCALAR_UNIT_TIME:
|
|
|
|
return ScalarUnit_Time(value).validate_scalar_unit()
|
2015-08-10 15:58:38 +05:30
|
|
|
elif type == Schema.VERSION:
|
|
|
|
return validateutils.TOSCAVersionProperty(value).get_version()
|
2014-12-18 11:06:29 +00:00
|
|
|
elif type == Schema.MAP:
|
2015-05-07 03:02:54 +08:00
|
|
|
validateutils.validate_map(value)
|
2014-12-18 11:06:29 +00:00
|
|
|
if entry_schema:
|
|
|
|
DataEntity.validate_entry(value, entry_schema, custom_def)
|
|
|
|
return value
|
2016-03-28 23:00:20 -05:00
|
|
|
elif type == Schema.PORTSPEC:
|
|
|
|
# TODO(TBD) bug 1567063, validate source & target as PortDef type
|
|
|
|
# as complex types not just as integers
|
|
|
|
PortSpec.validate_additional_req(value, prop_name, custom_def)
|
2014-12-18 11:06:29 +00:00
|
|
|
else:
|
|
|
|
data = DataEntity(type, value, custom_def)
|
|
|
|
return data.validate()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def validate_entry(value, entry_schema, custom_def=None):
|
|
|
|
'''Validate entries for map and list.'''
|
|
|
|
schema = Schema(None, entry_schema)
|
|
|
|
valuelist = value
|
|
|
|
if isinstance(value, dict):
|
|
|
|
valuelist = list(value.values())
|
|
|
|
for v in valuelist:
|
|
|
|
DataEntity.validate_datatype(schema.type, v, schema.entry_schema,
|
|
|
|
custom_def)
|
|
|
|
if schema.constraints:
|
|
|
|
for constraint in schema.constraints:
|
|
|
|
constraint.validate(v)
|
|
|
|
return value
|