2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.sdc.toscaparser.api;
23 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
24 import org.onap.sdc.toscaparser.api.elements.DataType;
25 import org.onap.sdc.toscaparser.api.elements.PortSpec;
26 import org.onap.sdc.toscaparser.api.elements.PropertyDef;
27 import org.onap.sdc.toscaparser.api.elements.ScalarUnitFrequency;
28 import org.onap.sdc.toscaparser.api.elements.ScalarUnitSize;
29 import org.onap.sdc.toscaparser.api.elements.ScalarUnitTime;
30 import org.onap.sdc.toscaparser.api.elements.constraints.Constraint;
31 import org.onap.sdc.toscaparser.api.elements.constraints.Schema;
32 import org.onap.sdc.toscaparser.api.functions.Function;
33 import org.onap.sdc.toscaparser.api.utils.TOSCAVersionProperty;
34 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
35 import org.onap.sdc.toscaparser.api.utils.ValidateUtils;
37 import java.util.ArrayList;
38 import java.util.LinkedHashMap;
39 import java.util.List;
41 public class DataEntity {
42 // A complex data value entity
44 private LinkedHashMap<String, Object> customDef;
45 private DataType dataType;
46 private LinkedHashMap<String, PropertyDef> schema;
48 private String propertyName;
50 public DataEntity(String _dataTypeName, Object _valueDict,
51 LinkedHashMap<String, Object> _customDef, String _propName) {
53 customDef = _customDef;
54 dataType = new DataType(_dataTypeName, _customDef);
55 schema = dataType.getAllProperties();
57 propertyName = _propName;
60 @SuppressWarnings("unchecked")
61 public Object validate() {
62 // Validate the value by the definition of the datatype
64 // A datatype can not have both 'type' and 'properties' definitions.
65 // If the datatype has 'type' definition
66 if (dataType.getValueType() != null) {
67 value = DataEntity.validateDatatype(dataType.getValueType(), value, null, customDef, null);
68 Schema schemaCls = new Schema(propertyName, dataType.getDefs());
69 for (Constraint constraint : schemaCls.getConstraints()) {
70 constraint.validate(value);
73 // If the datatype has 'properties' definition
75 if (!(value instanceof LinkedHashMap)) {
76 //ERROR under investigation
77 String checkedVal = value != null ? value.toString() : null;
79 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE001", String.format(
80 "TypeMismatchError: \"%s\" is not a map. The type is \"%s\"",
81 checkedVal, dataType.getType())));
83 if (value instanceof List && ((List) value).size() > 0) {
84 value = ((List) value).get(0);
87 if (!(value instanceof LinkedHashMap)) {
93 LinkedHashMap<String, Object> valueDict = (LinkedHashMap<String, Object>) value;
94 ArrayList<String> allowedProps = new ArrayList<>();
95 ArrayList<String> requiredProps = new ArrayList<>();
96 LinkedHashMap<String, Object> defaultProps = new LinkedHashMap<>();
98 allowedProps.addAll(schema.keySet());
99 for (String name : schema.keySet()) {
100 PropertyDef propDef = schema.get(name);
101 if (propDef.isRequired()) {
102 requiredProps.add(name);
104 if (propDef.getDefault() != null) {
105 defaultProps.put(name, propDef.getDefault());
110 // check allowed field
111 for (String valueKey : valueDict.keySet()) {
112 //1710 devlop JSON validation
113 if (!("json").equals(dataType.getType()) && !allowedProps.contains(valueKey)) {
114 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE100", String.format(
115 "UnknownFieldError: Data value of type \"%s\" contains unknown field \"%s\"",
116 dataType.getType(), valueKey)));
120 // check default field
121 for (String defKey : defaultProps.keySet()) {
122 Object defValue = defaultProps.get(defKey);
123 if (valueDict.get(defKey) == null) {
124 valueDict.put(defKey, defValue);
129 // check missing field
130 ArrayList<String> missingProp = new ArrayList<>();
131 for (String reqKey : requiredProps) {
132 if (!valueDict.keySet().contains(reqKey)) {
133 missingProp.add(reqKey);
136 if (missingProp.size() > 0) {
137 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE003", String.format(
138 "MissingRequiredFieldError: Data value of type \"%s\" is missing required field(s) \"%s\"",
139 dataType.getType(), missingProp.toString())));
143 for (String vname : valueDict.keySet()) {
144 Object vvalue = valueDict.get(vname);
145 LinkedHashMap<String, Object> schemaName = _findSchema(vname);
146 if (schemaName == null) {
149 Schema propSchema = new Schema(vname, schemaName);
150 // check if field value meets type defined
151 DataEntity.validateDatatype(propSchema.getType(),
153 propSchema.getEntrySchema(),
157 // check if field value meets constraints defined
158 if (propSchema.getConstraints() != null) {
159 for (Constraint constraint : propSchema.getConstraints()) {
160 if (vvalue instanceof ArrayList) {
161 for (Object val : (ArrayList<Object>) vvalue) {
162 constraint.validate(val);
165 constraint.validate(vvalue);
174 private LinkedHashMap<String, Object> _findSchema(String name) {
175 if (schema != null && schema.get(name) != null) {
176 return schema.get(name).getSchema();
181 public static Object validateDatatype(String type,
183 LinkedHashMap<String, Object> entrySchema,
184 LinkedHashMap<String, Object> customDef,
186 // Validate value with given type
188 // If type is list or map, validate its entry by entry_schema(if defined)
189 // If type is a user-defined complex datatype, custom_def is required.
191 if (Function.isFunction(value)) {
193 } else if (type == null) {
195 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE002", String.format(
196 "MissingType: Type is missing for value \"%s\"",
199 } else if (type.equals(Schema.STRING)) {
200 return ValidateUtils.validateString(value);
201 } else if (type.equals(Schema.INTEGER)) {
202 return ValidateUtils.validateInteger(value);
203 } else if (type.equals(Schema.FLOAT)) {
204 return ValidateUtils.validateFloat(value);
205 } else if (type.equals(Schema.NUMBER)) {
206 return ValidateUtils.validateNumeric(value);
207 } else if (type.equals(Schema.BOOLEAN)) {
208 return ValidateUtils.validateBoolean(value);
209 } else if (type.equals(Schema.RANGE)) {
210 return ValidateUtils.validateRange(value);
211 } else if (type.equals(Schema.TIMESTAMP)) {
212 ValidateUtils.validateTimestamp(value);
214 } else if (type.equals(Schema.LIST)) {
215 ValidateUtils.validateList(value);
216 if (entrySchema != null) {
217 DataEntity.validateEntry(value, entrySchema, customDef);
220 } else if (type.equals(Schema.SCALAR_UNIT_SIZE)) {
221 return (new ScalarUnitSize(value)).validateScalarUnit();
222 } else if (type.equals(Schema.SCALAR_UNIT_FREQUENCY)) {
223 return (new ScalarUnitFrequency(value)).validateScalarUnit();
224 } else if (type.equals(Schema.SCALAR_UNIT_TIME)) {
225 return (new ScalarUnitTime(value)).validateScalarUnit();
226 } else if (type.equals(Schema.VERSION)) {
227 return (new TOSCAVersionProperty(value.toString())).getVersion();
228 } else if (type.equals(Schema.MAP)) {
229 ValidateUtils.validateMap(value);
230 if (entrySchema != null) {
231 DataEntity.validateEntry(value, entrySchema, customDef);
234 } else if (type.equals(Schema.PORTSPEC)) {
235 // tODO(TBD) bug 1567063, validate source & target as PortDef type
236 // as complex types not just as integers
237 PortSpec.validateAdditionalReq(value, propName, customDef);
239 DataEntity data = new DataEntity(type, value, customDef, null);
240 return data.validate();
246 @SuppressWarnings("unchecked")
247 public static Object validateEntry(Object value,
248 LinkedHashMap<String, Object> entrySchema,
249 LinkedHashMap<String, Object> customDef) {
251 // Validate entries for map and list
252 Schema schema = new Schema(null, entrySchema);
253 Object valueob = value;
254 ArrayList<Object> valueList = null;
255 if (valueob instanceof LinkedHashMap) {
256 valueList = new ArrayList<Object>(((LinkedHashMap<String, Object>) valueob).values());
257 } else if (valueob instanceof ArrayList) {
258 valueList = (ArrayList<Object>) valueob;
260 if (valueList != null) {
261 for (Object v : valueList) {
262 DataEntity.validateDatatype(schema.getType(), v, schema.getEntrySchema(), customDef, null);
263 if (schema.getConstraints() != null) {
264 for (Constraint constraint : schema.getConstraints()) {
265 constraint.validate(v);
274 public String toString() {
275 return "DataEntity{" +
276 "customDef=" + customDef +
277 ", dataType=" + dataType +
278 ", schema=" + schema +
280 ", propertyName='" + propertyName + '\'' +
287 from toscaparser.common.exception import ValidationIssueCollector
288 from toscaparser.common.exception import MissingRequiredFieldError
289 from toscaparser.common.exception import TypeMismatchError
290 from toscaparser.common.exception import UnknownFieldError
291 from toscaparser.elements.constraints import Schema
292 from toscaparser.elements.datatype import DataType
293 from toscaparser.elements.portspectype import PortSpec
294 from toscaparser.elements.scalarunit import ScalarUnit_Frequency
295 from toscaparser.elements.scalarunit import ScalarUnit_Size
296 from toscaparser.elements.scalarunit import ScalarUnit_Time
297 from toscaparser.utils.gettextutils import _
298 from toscaparser.utils import validateutils
301 class DataEntity(object):
302 '''A complex data value entity.'''
304 def __init__(self, datatypename, value_dict, custom_def=None,
306 self.custom_def = custom_def
307 self.datatype = DataType(datatypename, custom_def)
308 self.schema = self.datatype.get_all_properties()
309 self.value = value_dict
310 self.property_name = prop_name
313 '''Validate the value by the definition of the datatype.'''
315 # A datatype can not have both 'type' and 'properties' definitions.
316 # If the datatype has 'type' definition
317 if self.datatype.value_type:
318 self.value = DataEntity.validate_datatype(self.datatype.value_type,
322 schema = Schema(self.property_name, self.datatype.defs)
323 for constraint in schema.constraints:
324 constraint.validate(self.value)
325 # If the datatype has 'properties' definition
327 if not isinstance(self.value, dict):
328 ValidationIssueCollector.appendException(
329 TypeMismatchError(what=self.value,
330 type=self.datatype.type))
335 allowed_props = self.schema.keys()
336 for name, prop_def in self.schema.items():
337 if prop_def.required:
338 required_props.append(name)
340 default_props[name] = prop_def.default
342 # check allowed field
343 for value_key in list(self.value.keys()):
344 if value_key not in allowed_props:
345 ValidationIssueCollector.appendException(
346 UnknownFieldError(what=(_('Data value of type "%s"')
347 % self.datatype.type),
350 # check default field
351 for def_key, def_value in list(default_props.items()):
352 if def_key not in list(self.value.keys()):
353 self.value[def_key] = def_value
355 # check missing field
357 for req_key in required_props:
358 if req_key not in list(self.value.keys()):
359 missingprop.append(req_key)
361 ValidationIssueCollector.appendException(
362 MissingRequiredFieldError(
363 what=(_('Data value of type "%s"')
364 % self.datatype.type), required=missingprop))
367 for name, value in list(self.value.items()):
368 schema_name = self._find_schema(name)
371 prop_schema = Schema(name, schema_name)
372 # check if field value meets type defined
373 DataEntity.validate_datatype(prop_schema.type, value,
374 prop_schema.entry_schema,
376 # check if field value meets constraints defined
377 if prop_schema.constraints:
378 for constraint in prop_schema.constraints:
379 if isinstance(value, list):
381 constraint.validate(val)
383 constraint.validate(value)
387 def _find_schema(self, name):
388 if self.schema and name in self.schema.keys():
389 return self.schema[name].schema
392 def validate_datatype(type, value, entry_schema=None, custom_def=None,
394 '''Validate value with given type.
396 If type is list or map, validate its entry by entry_schema(if defined)
397 If type is a user-defined complex datatype, custom_def is required.
399 from toscaparser.functions import is_function
400 if is_function(value):
402 if type == Schema.STRING:
403 return validateutils.validate_string(value)
404 elif type == Schema.INTEGER:
405 return validateutils.validate_integer(value)
406 elif type == Schema.FLOAT:
407 return validateutils.validate_float(value)
408 elif type == Schema.NUMBER:
409 return validateutils.validate_numeric(value)
410 elif type == Schema.BOOLEAN:
411 return validateutils.validate_boolean(value)
412 elif type == Schema.RANGE:
413 return validateutils.validate_range(value)
414 elif type == Schema.TIMESTAMP:
415 validateutils.validate_timestamp(value)
417 elif type == Schema.LIST:
418 validateutils.validate_list(value)
420 DataEntity.validate_entry(value, entry_schema, custom_def)
422 elif type == Schema.SCALAR_UNIT_SIZE:
423 return ScalarUnit_Size(value).validate_scalar_unit()
424 elif type == Schema.SCALAR_UNIT_FREQUENCY:
425 return ScalarUnit_Frequency(value).validate_scalar_unit()
426 elif type == Schema.SCALAR_UNIT_TIME:
427 return ScalarUnit_Time(value).validate_scalar_unit()
428 elif type == Schema.VERSION:
429 return validateutils.TOSCAVersionProperty(value).get_version()
430 elif type == Schema.MAP:
431 validateutils.validate_map(value)
433 DataEntity.validate_entry(value, entry_schema, custom_def)
435 elif type == Schema.PORTSPEC:
436 # tODO(TBD) bug 1567063, validate source & target as PortDef type
437 # as complex types not just as integers
438 PortSpec.validate_additional_req(value, prop_name, custom_def)
440 data = DataEntity(type, value, custom_def)
441 return data.validate()
444 def validate_entry(value, entry_schema, custom_def=None):
445 '''Validate entries for map and list.'''
446 schema = Schema(None, entry_schema)
448 if isinstance(value, dict):
449 valuelist = list(value.values())
451 DataEntity.validate_datatype(schema.type, v, schema.entry_schema,
453 if schema.constraints:
454 for constraint in schema.constraints:
455 constraint.validate(v)