2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2017 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.openecomp.sdc.be.model.tosca.validators;
 
  23 import java.util.HashMap;
 
  24 import java.util.List;
 
  26 import java.util.Map.Entry;
 
  29 import org.apache.commons.lang3.tuple.ImmutablePair;
 
  30 import org.openecomp.sdc.be.model.DataTypeDefinition;
 
  31 import org.openecomp.sdc.be.model.PropertyDefinition;
 
  32 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
 
  33 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
 
  34 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
 
  35 import org.slf4j.Logger;
 
  36 import org.slf4j.LoggerFactory;
 
  38 import com.google.gson.Gson;
 
  39 import com.google.gson.JsonElement;
 
  40 import com.google.gson.JsonObject;
 
  41 import com.google.gson.JsonParser;
 
  42 import com.google.gson.JsonPrimitive;
 
  43 import com.google.gson.JsonSyntaxException;
 
  45 public class DataTypeValidatorConverter {
 
  47         private static DataTypeValidatorConverter dataTypeValidatorConverter = new DataTypeValidatorConverter();
 
  49         public static DataTypeValidatorConverter getInstance() {
 
  50                 return dataTypeValidatorConverter;
 
  53         private DataTypeValidatorConverter() {
 
  57         private static Logger log = LoggerFactory.getLogger(DataTypeValidatorConverter.class.getName());
 
  59         JsonParser jsonParser = new JsonParser();
 
  61         ImmutablePair<JsonElement, Boolean> falseResult = new ImmutablePair<JsonElement, Boolean>(null, false);
 
  62         ImmutablePair<JsonElement, Boolean> trueEmptyResult = new ImmutablePair<JsonElement, Boolean>(null, true);
 
  64         ImmutablePair<String, Boolean> trueStringEmptyResult = new ImmutablePair<String, Boolean>(null, true);
 
  65         ImmutablePair<String, Boolean> falseStringEmptyResult = new ImmutablePair<String, Boolean>(null, true);
 
  67         private ToscaPropertyType isDataTypeDerviedFromScalarType(DataTypeDefinition dataTypeDef) {
 
  69                 ToscaPropertyType result = null;
 
  71                 DataTypeDefinition dataType = dataTypeDef;
 
  73                 while (dataType != null) {
 
  75                         String name = dataType.getName();
 
  76                         ToscaPropertyType typeIfScalar = ToscaPropertyType.getTypeIfScalar(name);
 
  77                         if (typeIfScalar != null) {
 
  78                                 result = typeIfScalar;
 
  82                         dataType = dataType.getDerivedFrom();
 
  88         private ImmutablePair<JsonElement, Boolean> validateAndUpdate(JsonElement jsonElement, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> allDataTypes) {
 
  90                 Map<String, PropertyDefinition> allProperties = getAllProperties(dataTypeDefinition);
 
  92                 ToscaPropertyType toscaPropertyType = null;
 
  93                 if ((toscaPropertyType = isDataTypeDerviedFromScalarType(dataTypeDefinition)) != null) {
 
  95                         PropertyTypeValidator validator = toscaPropertyType.getValidator();
 
  96                         PropertyValueConverter converter = toscaPropertyType.getConverter();
 
  97                         if (jsonElement == null || true == jsonElement.isJsonNull()) {
 
  98                                 boolean valid = validator.isValid(null, null, allDataTypes);
 
 100                                         log.trace("Failed in validation of property {} from type {}",  dataTypeDefinition.getName(), dataTypeDefinition.getName());
 
 103                                 return new ImmutablePair<JsonElement, Boolean>(jsonElement, true);
 
 106                                 if (jsonElement.isJsonPrimitive()) {
 
 108                                         if (jsonElement != null) {
 
 109                                                 if (jsonElement.toString().isEmpty()) {
 
 112                                                         value = jsonElement.toString();
 
 115                                         boolean valid = validator.isValid(value, null, null);
 
 117                                                 log.trace("Failed in validation of property {} from type {}. Json primitive value is {}", dataTypeDefinition.getName(), dataTypeDefinition.getName(), value);
 
 121                                         String convertedValue = converter.convert(value, null, allDataTypes);
 
 122                                         JsonElement element = null;
 
 124                                                 element = jsonParser.parse(convertedValue);
 
 125                                         } catch (JsonSyntaxException e) {
 
 126                                                 log.debug("Failed to parse value {} of property {} {}", convertedValue, dataTypeDefinition.getName(), e);
 
 130                                         return new ImmutablePair<JsonElement, Boolean>(element, true);
 
 133                                         // MAP, LIST, OTHER types cannot be applied data type
 
 134                                         // definition scalar type. We currently cannot derived from
 
 135                                         // map/list. (cannot add the entry schema to it)
 
 136                                         log.debug("We cannot derive from list/map. Thus, the value cannot be not primitive since the data type {} is scalar one", dataTypeDefinition.getName());
 
 143                         if (jsonElement == null || jsonElement.isJsonNull()) {
 
 145                                 return new ImmutablePair<JsonElement, Boolean>(jsonElement, true);
 
 149                                 if (jsonElement.isJsonObject()) {
 
 151                                         JsonObject buildJsonObject = new JsonObject();
 
 153                                         JsonObject asJsonObject = jsonElement.getAsJsonObject();
 
 154                                         Set<Entry<String, JsonElement>> entrySet = asJsonObject.entrySet();
 
 156                                         for (Entry<String, JsonElement> entry : entrySet) {
 
 157                                                 String propName = entry.getKey();
 
 159                                                 JsonElement elementValue = entry.getValue();
 
 161                                                 PropertyDefinition propertyDefinition = allProperties.get(propName);
 
 162                                                 if (propertyDefinition == null) {
 
 163                                                         log.debug("The property {} was not found under data type {}" ,propName, dataTypeDefinition.getName());
 
 166                                                 String type = propertyDefinition.getType();
 
 167                                                 boolean isScalarType = ToscaPropertyType.isScalarType(type);
 
 170                                                         ToscaPropertyType propertyType = ToscaPropertyType.isValidType(type);
 
 171                                                         if (propertyType == null) {
 
 172                                                                 log.debug("cannot find the {} under default tosca property types", type);
 
 175                                                         PropertyTypeValidator validator = propertyType.getValidator();
 
 176                                                         String innerType = null;
 
 177                                                         if (propertyType == ToscaPropertyType.LIST || propertyType == ToscaPropertyType.MAP) {
 
 178                                                                 if (propertyDefinition.getSchema() != null && propertyDefinition.getSchema().getProperty() != null) {
 
 179                                                                         innerType = propertyDefinition.getSchema().getProperty().getType();
 
 180                                                                         if (innerType == null) {
 
 181                                                                                 log.debug("Property type {} must have inner type in its declaration.", propertyType);
 
 188                                                         if (elementValue != null) {
 
 189                                                                 if (elementValue.isJsonPrimitive() && elementValue.getAsString().isEmpty()) {
 
 192                                                                         value = elementValue.toString();
 
 196                                                         boolean isValid = validator.isValid(value, innerType, allDataTypes);
 
 197                                                         if (false == isValid) {
 
 198                                                                 log.debug("Failed to validate the value {} from type {}", value, propertyType);
 
 202                                                         PropertyValueConverter converter = propertyType.getConverter();
 
 203                                                         String convertedValue = converter.convert(value, innerType, allDataTypes);
 
 205                                                         JsonElement element = null;
 
 206                                                         if (convertedValue != null) {
 
 207                                                                 if (convertedValue.isEmpty()) {
 
 208                                                                         element = new JsonPrimitive("");
 
 211                                                                                 element = jsonParser.parse(convertedValue);
 
 212                                                                         } catch (JsonSyntaxException e) {
 
 213                                                                                 log.debug("Failed to parse value {} of type {}", convertedValue, propertyType, e);
 
 218                                                         buildJsonObject.add(propName, element);
 
 222                                                         DataTypeDefinition typeDefinition = allDataTypes.get(type);
 
 223                                                         if (typeDefinition == null) {
 
 224                                                                 log.debug("The data type {} cannot be found in the given data type list.", type);
 
 228                                                         ImmutablePair<JsonElement, Boolean> isValid = validateAndUpdate(elementValue, typeDefinition, allDataTypes);
 
 230                                                         if (!isValid.getRight().booleanValue()) {
 
 231                                                                 log.debug("Failed in validation of value {} from type {}", (elementValue != null ? elementValue.toString() : null), typeDefinition.getName());
 
 235                                                         buildJsonObject.add(propName, isValid.getLeft());
 
 240                                         return new ImmutablePair<JsonElement, Boolean>(buildJsonObject, true);
 
 242                                         log.debug("The value {} of type {} should be json object", (jsonElement != null ? jsonElement.toString() : null), dataTypeDefinition.getName());
 
 251         public ImmutablePair<JsonElement, Boolean> validateAndUpdate(String value, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> allDataTypes) {
 
 253                 ImmutablePair<JsonElement, Boolean> result = falseResult;
 
 255                 if (value == null || value.isEmpty()) {
 
 256                         return trueEmptyResult;
 
 259                 JsonElement jsonElement = null;
 
 261                         jsonElement = jsonParser.parse(value);
 
 262                 } catch (JsonSyntaxException e) {
 
 266                 result = validateAndUpdate(jsonElement, dataTypeDefinition, allDataTypes);
 
 271         private Map<String, PropertyDefinition> getAllProperties(DataTypeDefinition dataTypeDefinition) {
 
 273                 Map<String, PropertyDefinition> allParentsProps = new HashMap<String, PropertyDefinition>();
 
 275                 while (dataTypeDefinition != null) {
 
 277                         List<PropertyDefinition> currentParentsProps = dataTypeDefinition.getProperties();
 
 278                         if (currentParentsProps != null) {
 
 279                                 currentParentsProps.stream().forEach(p -> allParentsProps.put(p.getName(), p));
 
 282                         dataTypeDefinition = dataTypeDefinition.getDerivedFrom();
 
 285                 return allParentsProps;
 
 288         public boolean isValid(String value, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> allDataTypes) {
 
 290                 boolean result = false;
 
 292                 if (value == null || value.isEmpty()) {
 
 296                 JsonElement jsonElement = null;
 
 298                         jsonElement = jsonParser.parse(value);
 
 299                 } catch (JsonSyntaxException e) {
 
 300                         log.debug("Failed to parse the value {} from type {}", value, dataTypeDefinition, e);
 
 304                 result = isValid(jsonElement, dataTypeDefinition, allDataTypes);
 
 309         private boolean isValid(JsonElement jsonElement, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> allDataTypes) {
 
 311                 Map<String, PropertyDefinition> allProperties = getAllProperties(dataTypeDefinition);
 
 313                 ToscaPropertyType toscaPropertyType = null;
 
 314                 if ((toscaPropertyType = isDataTypeDerviedFromScalarType(dataTypeDefinition)) != null) {
 
 316                         PropertyTypeValidator validator = toscaPropertyType.getValidator();
 
 317                         if (jsonElement == null || true == jsonElement.isJsonNull()) {
 
 318                                 boolean valid = validator.isValid(null, null, allDataTypes);
 
 319                                 if (false == valid) {
 
 320                                         log.trace("Failed in validation of property {} from type {}", dataTypeDefinition.getName(), dataTypeDefinition.getName());
 
 327                                 if (true == jsonElement.isJsonPrimitive()) {
 
 329                                         if (jsonElement != null) {
 
 330                                                 if (jsonElement.toString().isEmpty()) {
 
 333                                                         value = jsonElement.toString();
 
 336                                         boolean valid = validator.isValid(value, null, allDataTypes);
 
 337                                         if (false == valid) {
 
 338                                                 log.trace("Failed in validation of property {} from type {}. Json primitive value is {}", dataTypeDefinition.getName(), dataTypeDefinition.getName(), value);
 
 345                                         // MAP, LIST, OTHER types cannot be applied data type
 
 346                                         // definition scalar type. We currently cannot derived from
 
 347                                         // map/list. (cannot add the entry schema to it)
 
 348                                         log.debug("We cannot derive from list/map. Thus, the value cannot be not primitive since the data type {} is scalar one", dataTypeDefinition.getName());
 
 355                         if (jsonElement == null || jsonElement.isJsonNull()) {
 
 361                                 if (jsonElement.isJsonObject()) {
 
 363                                         JsonObject asJsonObject = jsonElement.getAsJsonObject();
 
 364                                         Set<Entry<String, JsonElement>> entrySet = asJsonObject.entrySet();
 
 366                                         for (Entry<String, JsonElement> entry : entrySet) {
 
 367                                                 String propName = entry.getKey();
 
 369                                                 JsonElement elementValue = entry.getValue();
 
 371                                                 PropertyDefinition propertyDefinition = allProperties.get(propName);
 
 372                                                 if (propertyDefinition == null) {
 
 373                                                         log.debug("The property {} was not found under data type {}", propName, dataTypeDefinition.getName());
 
 376                                                 String type = propertyDefinition.getType();
 
 377                                                 boolean isScalarType = ToscaPropertyType.isScalarType(type);
 
 379                                                 if (true == isScalarType) {
 
 380                                                         ToscaPropertyType propertyType = ToscaPropertyType.isValidType(type);
 
 381                                                         if (propertyType == null) {
 
 382                                                                 log.debug("cannot find the {} under default tosca property types", type);
 
 385                                                         PropertyTypeValidator validator = propertyType.getValidator();
 
 386                                                         String innerType = null;
 
 387                                                         if (propertyType == ToscaPropertyType.LIST || propertyType == ToscaPropertyType.MAP) {
 
 388                                                                 if (propertyDefinition.getSchema() != null && propertyDefinition.getSchema().getProperty() != null) {
 
 389                                                                         innerType = propertyDefinition.getSchema().getProperty().getType();
 
 390                                                                         if (innerType == null) {
 
 391                                                                                 log.debug("Property type {} must have inner type in its declaration.", propertyType);
 
 398                                                         if (elementValue != null) {
 
 399                                                                 if (elementValue.isJsonPrimitive() && elementValue.getAsString().isEmpty()) {
 
 402                                                                         value = elementValue.toString();
 
 406                                                         boolean isValid = validator.isValid(value, innerType, allDataTypes);
 
 407                                                         if (false == isValid) {
 
 408                                                                 log.debug("Failed to validate the value {} from type {}", value, propertyType);
 
 414                                                         DataTypeDefinition typeDefinition = allDataTypes.get(type);
 
 415                                                         if (typeDefinition == null) {
 
 416                                                                 log.debug("The data type {} cannot be found in the given data type list.", type);
 
 420                                                         boolean isValid = isValid(elementValue, typeDefinition, allDataTypes);
 
 422                                                         if (false == isValid) {
 
 423                                                                 log.debug("Failed in validation of value {} from type {}", (elementValue != null ? elementValue.toString() : null), typeDefinition.getName());
 
 433                                         log.debug("The value {} of type {} should be json object", (jsonElement != null ? jsonElement.toString() : null), dataTypeDefinition.getName());