1 package org.onap.sdc.toscaparser.api;
3 import java.util.ArrayList;
4 import java.util.LinkedHashMap;
7 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
8 import org.onap.sdc.toscaparser.api.elements.*;
9 import org.onap.sdc.toscaparser.api.elements.constraints.Constraint;
10 import org.onap.sdc.toscaparser.api.elements.constraints.Schema;
11 import org.onap.sdc.toscaparser.api.functions.Function;
12 import org.onap.sdc.toscaparser.api.utils.TOSCAVersionProperty;
13 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
14 import org.onap.sdc.toscaparser.api.utils.ValidateUtils;
16 public class DataEntity {
17 // A complex data value entity
19 private LinkedHashMap<String,Object> customDef;
20 private DataType dataType;
21 private LinkedHashMap<String,PropertyDef> schema;
23 private String propertyName;
25 public DataEntity(String _dataTypeName,Object _valueDict,
26 LinkedHashMap<String,Object> _customDef,String _propName) {
28 customDef = _customDef;
29 dataType = new DataType(_dataTypeName,_customDef);
30 schema = dataType.getAllProperties();
32 propertyName = _propName;
35 @SuppressWarnings("unchecked")
36 public Object validate() {
37 // Validate the value by the definition of the datatype
39 // A datatype can not have both 'type' and 'properties' definitions.
40 // If the datatype has 'type' definition
41 if(dataType.getValueType() != null) {
42 value = DataEntity.validateDatatype(dataType.getValueType(),value,null,customDef,null);
43 Schema schemaCls = new Schema(propertyName,dataType.getDefs());
44 for(Constraint constraint: schemaCls.getConstraints()) {
45 constraint.validate(value);
48 // If the datatype has 'properties' definition
50 if(!(value instanceof LinkedHashMap)) {
51 //ERROR under investigation
52 String checkedVal = value != null ? value.toString() : null;
54 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE001", String.format(
55 "TypeMismatchError: \"%s\" is not a map. The type is \"%s\"",
56 checkedVal, dataType.getType())));
58 if (value instanceof List && ((List) value).size() > 0) {
59 value = ((List) value).get(0);
62 if (!(value instanceof LinkedHashMap)) {
69 LinkedHashMap<String,Object> valueDict = (LinkedHashMap<String,Object>)value;
70 ArrayList<String> allowedProps = new ArrayList<>();
71 ArrayList<String> requiredProps = new ArrayList<>();
72 LinkedHashMap<String,Object> defaultProps = new LinkedHashMap<>();
74 allowedProps.addAll(schema.keySet());
75 for(String name: schema.keySet()) {
76 PropertyDef propDef = schema.get(name);
77 if(propDef.isRequired()) {
78 requiredProps.add(name);
80 if(propDef.getDefault() != null) {
81 defaultProps.put(name,propDef.getDefault());
86 // check allowed field
87 for(String valueKey: valueDict.keySet()) {
88 //1710 devlop JSON validation
89 if(!("json").equals(dataType.getType()) && !allowedProps.contains(valueKey)) {
90 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE100", String.format(
91 "UnknownFieldError: Data value of type \"%s\" contains unknown field \"%s\"",
92 dataType.getType(),valueKey)));
96 // check default field
97 for(String defKey: defaultProps.keySet()) {
98 Object defValue = defaultProps.get(defKey);
99 if(valueDict.get(defKey) == null) {
100 valueDict.put(defKey, defValue);
105 // check missing field
106 ArrayList<String> missingProp = new ArrayList<>();
107 for(String reqKey: requiredProps) {
108 if(!valueDict.keySet().contains(reqKey)) {
109 missingProp.add(reqKey);
112 if(missingProp.size() > 0) {
113 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE003",String.format(
114 "MissingRequiredFieldError: Data value of type \"%s\" is missing required field(s) \"%s\"",
115 dataType.getType(),missingProp.toString())));
119 for(String vname: valueDict.keySet()) {
120 Object vvalue = valueDict.get(vname);
121 LinkedHashMap<String,Object> schemaName = _findSchema(vname);
122 if(schemaName == null) {
125 Schema propSchema = new Schema(vname,schemaName);
126 // check if field value meets type defined
127 DataEntity.validateDatatype(propSchema.getType(),
129 propSchema.getEntrySchema(),
133 // check if field value meets constraints defined
134 if(propSchema.getConstraints() != null) {
135 for(Constraint constraint: propSchema.getConstraints()) {
136 if(vvalue instanceof ArrayList) {
137 for(Object val: (ArrayList<Object>)vvalue) {
138 constraint.validate(val);
142 constraint.validate(vvalue);
151 private LinkedHashMap<String,Object> _findSchema(String name) {
152 if(schema != null && schema.get(name) != null) {
153 return schema.get(name).getSchema();
158 public static Object validateDatatype(String type,
160 LinkedHashMap<String,Object> entrySchema,
161 LinkedHashMap<String,Object> customDef,
163 // Validate value with given type
165 // If type is list or map, validate its entry by entry_schema(if defined)
166 // If type is a user-defined complex datatype, custom_def is required.
168 if(Function.isFunction(value)) {
171 else if (type == null) {
173 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE002", String.format(
174 "MissingType: Type is missing for value \"%s\"",
178 else if(type.equals(Schema.STRING)) {
179 return ValidateUtils.validateString(value);
181 else if(type.equals(Schema.INTEGER)) {
182 return ValidateUtils.validateInteger(value);
184 else if(type.equals(Schema.FLOAT)) {
185 return ValidateUtils.validateFloat(value);
187 else if(type.equals(Schema.NUMBER)) {
188 return ValidateUtils.validateNumeric(value);
190 else if(type.equals(Schema.BOOLEAN)) {
191 return ValidateUtils.validateBoolean(value);
193 else if(type.equals(Schema.RANGE)) {
194 return ValidateUtils.validateRange(value);
196 else if(type.equals(Schema.TIMESTAMP)) {
197 ValidateUtils.validateTimestamp(value);
200 else if(type.equals(Schema.LIST)) {
201 ValidateUtils.validateList(value);
202 if(entrySchema != null) {
203 DataEntity.validateEntry(value,entrySchema,customDef);
207 else if(type.equals(Schema.SCALAR_UNIT_SIZE)) {
208 return (new ScalarUnitSize(value)).validateScalarUnit();
210 else if(type.equals(Schema.SCALAR_UNIT_FREQUENCY)) {
211 return (new ScalarUnitFrequency(value)).validateScalarUnit();
213 else if(type.equals(Schema.SCALAR_UNIT_TIME)) {
214 return (new ScalarUnitTime(value)).validateScalarUnit();
216 else if(type.equals(Schema.VERSION)) {
217 return (new TOSCAVersionProperty(value)).getVersion();
219 else if(type.equals(Schema.MAP)) {
220 ValidateUtils.validateMap(value);
221 if(entrySchema != null) {
222 DataEntity.validateEntry(value,entrySchema,customDef);
226 else if(type.equals(Schema.PORTSPEC)) {
227 // tODO(TBD) bug 1567063, validate source & target as PortDef type
228 // as complex types not just as integers
229 PortSpec.validateAdditionalReq(value,propName,customDef);
232 DataEntity data = new DataEntity(type,value,customDef,null);
233 return data.validate();
239 @SuppressWarnings("unchecked")
240 public static Object validateEntry(Object value,
241 LinkedHashMap<String,Object> entrySchema,
242 LinkedHashMap<String,Object> customDef) {
244 // Validate entries for map and list
245 Schema schema = new Schema(null,entrySchema);
246 Object valueob = value;
247 ArrayList<Object> valueList = null;
248 if(valueob instanceof LinkedHashMap) {
249 valueList = new ArrayList<Object>(((LinkedHashMap<String,Object>)valueob).values());
251 else if(valueob instanceof ArrayList) {
252 valueList = (ArrayList<Object>)valueob;
254 if(valueList != null) {
255 for(Object v: valueList) {
256 DataEntity.validateDatatype(schema.getType(),v,schema.getEntrySchema(),customDef,null);
257 if(schema.getConstraints() != null) {
258 for(Constraint constraint: schema.getConstraints()) {
259 constraint.validate(v);
268 public String toString() {
269 return "DataEntity{" +
270 "customDef=" + customDef +
271 ", dataType=" + dataType +
272 ", schema=" + schema +
274 ", propertyName='" + propertyName + '\'' +
281 from toscaparser.common.exception import ValidationIssueCollector
282 from toscaparser.common.exception import MissingRequiredFieldError
283 from toscaparser.common.exception import TypeMismatchError
284 from toscaparser.common.exception import UnknownFieldError
285 from toscaparser.elements.constraints import Schema
286 from toscaparser.elements.datatype import DataType
287 from toscaparser.elements.portspectype import PortSpec
288 from toscaparser.elements.scalarunit import ScalarUnit_Frequency
289 from toscaparser.elements.scalarunit import ScalarUnit_Size
290 from toscaparser.elements.scalarunit import ScalarUnit_Time
291 from toscaparser.utils.gettextutils import _
292 from toscaparser.utils import validateutils
295 class DataEntity(object):
296 '''A complex data value entity.'''
298 def __init__(self, datatypename, value_dict, custom_def=None,
300 self.custom_def = custom_def
301 self.datatype = DataType(datatypename, custom_def)
302 self.schema = self.datatype.get_all_properties()
303 self.value = value_dict
304 self.property_name = prop_name
307 '''Validate the value by the definition of the datatype.'''
309 # A datatype can not have both 'type' and 'properties' definitions.
310 # If the datatype has 'type' definition
311 if self.datatype.value_type:
312 self.value = DataEntity.validate_datatype(self.datatype.value_type,
316 schema = Schema(self.property_name, self.datatype.defs)
317 for constraint in schema.constraints:
318 constraint.validate(self.value)
319 # If the datatype has 'properties' definition
321 if not isinstance(self.value, dict):
322 ValidationIssueCollector.appendException(
323 TypeMismatchError(what=self.value,
324 type=self.datatype.type))
329 allowed_props = self.schema.keys()
330 for name, prop_def in self.schema.items():
331 if prop_def.required:
332 required_props.append(name)
334 default_props[name] = prop_def.default
336 # check allowed field
337 for value_key in list(self.value.keys()):
338 if value_key not in allowed_props:
339 ValidationIssueCollector.appendException(
340 UnknownFieldError(what=(_('Data value of type "%s"')
341 % self.datatype.type),
344 # check default field
345 for def_key, def_value in list(default_props.items()):
346 if def_key not in list(self.value.keys()):
347 self.value[def_key] = def_value
349 # check missing field
351 for req_key in required_props:
352 if req_key not in list(self.value.keys()):
353 missingprop.append(req_key)
355 ValidationIssueCollector.appendException(
356 MissingRequiredFieldError(
357 what=(_('Data value of type "%s"')
358 % self.datatype.type), required=missingprop))
361 for name, value in list(self.value.items()):
362 schema_name = self._find_schema(name)
365 prop_schema = Schema(name, schema_name)
366 # check if field value meets type defined
367 DataEntity.validate_datatype(prop_schema.type, value,
368 prop_schema.entry_schema,
370 # check if field value meets constraints defined
371 if prop_schema.constraints:
372 for constraint in prop_schema.constraints:
373 if isinstance(value, list):
375 constraint.validate(val)
377 constraint.validate(value)
381 def _find_schema(self, name):
382 if self.schema and name in self.schema.keys():
383 return self.schema[name].schema
386 def validate_datatype(type, value, entry_schema=None, custom_def=None,
388 '''Validate value with given type.
390 If type is list or map, validate its entry by entry_schema(if defined)
391 If type is a user-defined complex datatype, custom_def is required.
393 from toscaparser.functions import is_function
394 if is_function(value):
396 if type == Schema.STRING:
397 return validateutils.validate_string(value)
398 elif type == Schema.INTEGER:
399 return validateutils.validate_integer(value)
400 elif type == Schema.FLOAT:
401 return validateutils.validate_float(value)
402 elif type == Schema.NUMBER:
403 return validateutils.validate_numeric(value)
404 elif type == Schema.BOOLEAN:
405 return validateutils.validate_boolean(value)
406 elif type == Schema.RANGE:
407 return validateutils.validate_range(value)
408 elif type == Schema.TIMESTAMP:
409 validateutils.validate_timestamp(value)
411 elif type == Schema.LIST:
412 validateutils.validate_list(value)
414 DataEntity.validate_entry(value, entry_schema, custom_def)
416 elif type == Schema.SCALAR_UNIT_SIZE:
417 return ScalarUnit_Size(value).validate_scalar_unit()
418 elif type == Schema.SCALAR_UNIT_FREQUENCY:
419 return ScalarUnit_Frequency(value).validate_scalar_unit()
420 elif type == Schema.SCALAR_UNIT_TIME:
421 return ScalarUnit_Time(value).validate_scalar_unit()
422 elif type == Schema.VERSION:
423 return validateutils.TOSCAVersionProperty(value).get_version()
424 elif type == Schema.MAP:
425 validateutils.validate_map(value)
427 DataEntity.validate_entry(value, entry_schema, custom_def)
429 elif type == Schema.PORTSPEC:
430 # tODO(TBD) bug 1567063, validate source & target as PortDef type
431 # as complex types not just as integers
432 PortSpec.validate_additional_req(value, prop_name, custom_def)
434 data = DataEntity(type, value, custom_def)
435 return data.validate()
438 def validate_entry(value, entry_schema, custom_def=None):
439 '''Validate entries for map and list.'''
440 schema = Schema(None, entry_schema)
442 if isinstance(value, dict):
443 valuelist = list(value.values())
445 DataEntity.validate_datatype(schema.type, v, schema.entry_schema,
447 if schema.constraints:
448 for constraint in schema.constraints:
449 constraint.validate(v)