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.utils;
23 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
25 import java.util.ArrayList;
26 import java.util.Date;
27 import java.util.LinkedHashMap;
29 public class ValidateUtils {
31 private static final String RANGE_UNBOUNDED = "UNBOUNDED";
33 private ValidateUtils() {
36 public static Object strToNum(Object value) {
37 // Convert a string representation of a number into a numeric type
38 // TODO(TBD) we should not allow numeric values in, input should be str
39 if (value instanceof Number) {
43 return Integer.parseInt((String) value);
44 } catch (NumberFormatException e) {
47 return Float.parseFloat((String) value);
48 } catch (Exception e) {
53 public static Object validateNumeric(Object value) {
55 if (!(value instanceof Number)) {
56 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE257", String.format(
57 "ValueError: \"%s\" is not a numeric", value.toString())));
63 public static Object validateInteger(Object value) {
65 if (!(value instanceof Integer)) {
66 // allow "true" and "false"
67 if (value instanceof Boolean) {
68 return (Boolean) value ? 1 : 0;
70 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE258", String.format(
71 "ValueError: \"%s\" is not an integer", value.toString())));
77 public static Object validateFloat(Object value) {
79 if (!(value instanceof Float || value instanceof Double)) {
80 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE259", String.format(
81 "ValueError: \"%s\" is not a float", value.toString())));
87 public static Object validateString(Object value) {
89 if (!(value instanceof String)) {
90 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE260", String.format(
91 "ValueError: \'%s\' is not a string", value.toString())));
97 public static Object validateList(Object value) {
99 if (!(value instanceof ArrayList)) {
100 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE261", String.format(
101 "ValueError: \"%s\" is not a list", value.toString())));
108 @SuppressWarnings("unchecked")
109 public static Object validateRange(Object range) {
112 // validate range list has a min and max
113 if (range instanceof ArrayList && ((ArrayList<Object>) range).size() != 2) {
114 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE262", String.format(
115 "ValueError: \"%s\" is not a valid range", range.toString())));
116 // too dangerous to continue...
119 // validate min and max are numerics or the keyword UNBOUNDED
120 boolean minTest = false;
121 boolean maxTest = false;
122 Object r0 = ((ArrayList<Object>) range).get(0);
123 Object r1 = ((ArrayList<Object>) range).get(1);
125 if (!(r0 instanceof Integer) && !(r0 instanceof Float)
126 || !(r1 instanceof Integer) && !(r1 instanceof Float)) {
127 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE263", String.format(
128 "ValueError: \"%s\" is not a valid range", range.toString())));
129 // too dangerous to continue...
135 if (r0 instanceof String && ((String) r0).equals(RANGE_UNBOUNDED)) {
138 min = r0 instanceof Integer ? ((Integer) r0).floatValue() : (Float) r0;
140 if (r1 instanceof String && ((String) r1).equals(RANGE_UNBOUNDED)) {
143 max = r1 instanceof Integer ? ((Integer) r1).floatValue() : (Float) r1;
146 // validate the max > min (account for UNBOUNDED)
147 if (!minTest && !maxTest) {
148 // Note: min == max is allowed
150 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE264", String.format(
151 "ValueError:\"%s\" is not a valid range", range.toString())));
157 @SuppressWarnings("unchecked")
158 public static Object validateValueInRange(Object value, Object range, String propName) {
159 // verify all 3 are numeric and convert to Floats
160 if (!(value instanceof Integer || value instanceof Float)) {
161 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE265", String.format(
162 "ValueError: validateInRange: \"%s\" is not a number", range.toString())));
165 Float fval = value instanceof Integer ? ((Integer) value).floatValue() : (Float) value;
167 //////////////////////////
168 //"validateRange(range);"
169 //////////////////////////
170 // better safe than sorry...
171 // validate that range list has a min and max
172 if (range instanceof ArrayList && ((ArrayList<Object>) range).size() != 2) {
173 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE266", String.format(
174 "ValueError: \"%s\" is not a valid range", range.toString())));
175 // too dangerous to continue...
178 // validate min and max are numerics or the keyword UNBOUNDED
179 boolean minTest = false;
180 boolean maxTest = false;
181 Object r0 = ((ArrayList<Object>) range).get(0);
182 Object r1 = ((ArrayList<Object>) range).get(1);
184 if (!(r0 instanceof Integer) && !(r0 instanceof Float)
185 || !(r1 instanceof Integer) && !(r1 instanceof Float)) {
186 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE267", String.format(
187 "ValueError: \"%s\" is not a valid range", range.toString())));
188 // too dangerous to continue...
194 if (r0 instanceof String && ((String) r0).equals(RANGE_UNBOUNDED)) {
197 min = r0 instanceof Integer ? ((Integer) r0).floatValue() : (Float) r0;
199 if (r1 instanceof String && ((String) r1).equals(RANGE_UNBOUNDED)) {
202 max = r1 instanceof Integer ? ((Integer) r1).floatValue() : (Float) r1;
205 // validate the max > min (account for UNBOUNDED)
206 if (!minTest && !maxTest) {
207 // Note: min == max is allowed
209 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE268", String.format(
210 "ValueError:\"%s\" is not a valid range", range.toString())));
214 boolean bError = false;
215 //Note: value is valid if equal to min
221 // Note: value is valid if equal to max
228 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE269", String.format(
229 "RangeValueError: Property \"%s\", \"%s\" not in range [\"%s\" - \"%s\"",
230 propName, value.toString(), r0.toString(), r1.toString())));
235 public static Object validateMap(Object ob) {
237 if (!(ob instanceof LinkedHashMap)) {
238 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE270", String.format(
239 "ValueError\"%s\" is not a map.", ob.toString())));
245 public static Object validateBoolean(Object value) {
247 if (value instanceof Boolean) {
250 if (value instanceof String) {
251 String normalized = ((String) value).toLowerCase();
252 if (normalized.equals("true") || normalized.equals("false")) {
253 return normalized.equals("true");
256 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE271", String.format(
257 "ValueError: \"%s\" is not a boolean", value.toString())));
262 public static Object validateTimestamp(Object value) {
266 # Note: we must return our own exception message
267 # as dateutil's parser returns different types / values on
268 # different systems. OSX, for example, returns a tuple
269 # containing a different error message than Linux
270 dateutil.parser.parse(value)
271 except Exception as e:
272 original_err_msg = str(e)
273 log.error(original_err_msg)
274 ValidationIssueCollector.appendException(
275 ValueError(_('"%(val)s" is not a valid timestamp. "%(msg)s"') %
276 {'val': value, 'msg': original_err_msg}))
278 // timestamps are loaded as Date objects by the YAML parser
280 if (!(value instanceof Date)) {
281 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE272", String.format(
282 "ValueError: \"%s\" is not a valid timestamp",
294 from toscaparser.elements import constraints
295 from toscaparser.common.exception import ValidationIssueCollector
296 from toscaparser.common.exception import InvalidTOSCAVersionPropertyException
297 from toscaparser.common.exception import RangeValueError
298 from toscaparser.utils.gettextutils import _
300 log = logging.getLogger('tosca')
302 RANGE_UNBOUNDED = 'UNBOUNDED'
305 def str_to_num(value):
306 '''Convert a string representation of a number into a numeric type.'''
307 # tODO(TBD) we should not allow numeric values in, input should be str
308 if isinstance(value, numbers.Number):
316 def validate_numeric(value):
317 if not isinstance(value, numbers.Number):
318 ValidationIssueCollector.appendException(
319 ValueError(_('"%s" is not a numeric.') % value))
323 def validate_integer(value):
324 if not isinstance(value, int):
328 ValidationIssueCollector.appendException(
329 ValueError(_('"%s" is not an integer.') % value))
333 def validate_float(value):
334 if not isinstance(value, float):
335 ValidationIssueCollector.appendException(
336 ValueError(_('"%s" is not a float.') % value))
340 def validate_string(value):
341 if not isinstance(value, six.string_types):
342 ValidationIssueCollector.appendException(
343 ValueError(_('"%s" is not a string.') % value))
347 def validate_list(value):
348 if not isinstance(value, list):
349 ValidationIssueCollector.appendException(
350 ValueError(_('"%s" is not a list.') % value))
354 def validate_range(range):
357 # validate range list has a min and max
359 ValidationIssueCollector.appendException(
360 ValueError(_('"%s" is not a valid range.') % range))
361 # validate min and max are numerics or the keyword UNBOUNDED
362 min_test = max_test = False
363 if not range[0] == RANGE_UNBOUNDED:
364 min = validate_numeric(range[0])
367 if not range[1] == RANGE_UNBOUNDED:
368 max = validate_numeric(range[1])
371 # validate the max > min (account for UNBOUNDED)
372 if not min_test and not max_test:
373 # Note: min == max is allowed
375 ValidationIssueCollector.appendException(
376 ValueError(_('"%s" is not a valid range.') % range))
381 def validate_value_in_range(value, range, prop_name):
382 validate_numeric(value)
383 validate_range(range)
385 # Note: value is valid if equal to min
386 if range[0] != RANGE_UNBOUNDED:
388 ValidationIssueCollector.appendException(
389 RangeValueError(pname=prop_name,
393 # Note: value is valid if equal to max
394 if range[1] != RANGE_UNBOUNDED:
396 ValidationIssueCollector.appendException(
397 RangeValueError(pname=prop_name,
404 def validate_map(value):
405 if not isinstance(value, collections.Mapping):
406 ValidationIssueCollector.appendException(
407 ValueError(_('"%s" is not a map.') % value))
411 def validate_boolean(value):
412 if isinstance(value, bool):
415 if isinstance(value, str):
416 normalised = value.lower()
417 if normalised in ['true', 'false']:
418 return normalised == 'true'
420 ValidationIssueCollector.appendException(
421 ValueError(_('"%s" is not a boolean.') % value))
424 def validate_timestamp(value):
426 # Note: we must return our own exception message
427 # as dateutil's parser returns different types / values on
428 # different systems. OSX, for example, returns a tuple
429 # containing a different error message than Linux
430 dateutil.parser.parse(value)
431 except Exception as e:
432 original_err_msg = str(e)
433 log.error(original_err_msg)
434 ValidationIssueCollector.appendException(
435 ValueError(_('"%(val)s" is not a valid timestamp. "%(msg)s"') %
436 {'val': value, 'msg': original_err_msg}))