Fix property validation for data type in model
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / PropertyOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20 package org.openecomp.sdc.be.model.operations.impl;
21
22 import static org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR;
23
24 import com.fasterxml.jackson.core.ObjectCodec;
25 import com.fasterxml.jackson.databind.DeserializationContext;
26 import com.fasterxml.jackson.databind.JsonNode;
27 import com.google.common.collect.Maps;
28 import com.google.gson.JsonArray;
29 import com.google.gson.JsonDeserializationContext;
30 import com.google.gson.JsonDeserializer;
31 import com.google.gson.JsonElement;
32 import com.google.gson.JsonObject;
33 import com.google.gson.JsonParseException;
34 import com.google.gson.JsonParser;
35 import com.google.gson.JsonSerializationContext;
36 import com.google.gson.JsonSerializer;
37 import fj.data.Either;
38 import java.io.IOException;
39 import java.lang.reflect.Type;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Map.Entry;
47 import java.util.Set;
48 import java.util.StringJoiner;
49 import java.util.function.Consumer;
50 import java.util.regex.Matcher;
51 import java.util.regex.Pattern;
52 import java.util.stream.Collectors;
53 import org.apache.commons.collections.CollectionUtils;
54 import org.apache.commons.collections.MapUtils;
55 import org.apache.commons.lang3.StringUtils;
56 import org.apache.commons.lang3.tuple.ImmutablePair;
57 import org.apache.tinkerpop.gremlin.structure.Edge;
58 import org.apache.tinkerpop.gremlin.structure.Vertex;
59 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
60 import org.janusgraph.core.JanusGraph;
61 import org.janusgraph.core.JanusGraphVertex;
62 import org.janusgraph.core.JanusGraphVertexProperty;
63 import org.openecomp.sdc.be.config.BeEcompErrorManager;
64 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
65 import org.openecomp.sdc.be.dao.graph.GraphElementFactory;
66 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
67 import org.openecomp.sdc.be.dao.graph.datatype.GraphElementTypeEnum;
68 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
69 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
70 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
71 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
72 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
73 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
74 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
75 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
76 import org.openecomp.sdc.be.datatypes.elements.PropertyRule;
77 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
78 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
79 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
80 import org.openecomp.sdc.be.model.DataTypeDefinition;
81 import org.openecomp.sdc.be.model.IComplexDefaultValue;
82 import org.openecomp.sdc.be.model.PropertyConstraint;
83 import org.openecomp.sdc.be.model.PropertyDefinition;
84 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
85 import org.openecomp.sdc.be.model.operations.api.IPropertyOperation;
86 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
87 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
88 import org.openecomp.sdc.be.model.tosca.constraints.ConstraintType;
89 import org.openecomp.sdc.be.model.tosca.constraints.GreaterOrEqualConstraint;
90 import org.openecomp.sdc.be.model.tosca.constraints.GreaterThanConstraint;
91 import org.openecomp.sdc.be.model.tosca.constraints.InRangeConstraint;
92 import org.openecomp.sdc.be.model.tosca.constraints.LessOrEqualConstraint;
93 import org.openecomp.sdc.be.model.tosca.constraints.LessThanConstraint;
94 import org.openecomp.sdc.be.model.tosca.constraints.MinLengthConstraint;
95 import org.openecomp.sdc.be.model.tosca.constraints.ValidValuesConstraint;
96 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
97 import org.openecomp.sdc.be.resources.data.ComponentInstanceData;
98 import org.openecomp.sdc.be.resources.data.DataTypeData;
99 import org.openecomp.sdc.be.resources.data.ModelData;
100 import org.openecomp.sdc.be.resources.data.PropertyData;
101 import org.openecomp.sdc.be.resources.data.PropertyValueData;
102 import org.openecomp.sdc.be.resources.data.ResourceMetadataData;
103 import org.openecomp.sdc.be.resources.data.UniqueIdData;
104 import org.openecomp.sdc.common.log.wrappers.Logger;
105 import org.springframework.beans.factory.annotation.Autowired;
106 import org.springframework.stereotype.Component;
107
108 @Component("property-operation")
109 public class PropertyOperation extends AbstractOperation implements IPropertyOperation {
110
111     private static final String AFTER_RETRIEVING_DERIVED_FROM_NODE_OF_STATUS_IS = "After retrieving DERIVED_FROM node of {}. status is {}";
112     private static final String FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE = "Failed to fetch properties of data type {}";
113     private static final String DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS = "Data type {} cannot be found in graph. status is {}";
114     private static final String GOING_TO_EXECUTE_COMMIT_ON_GRAPH = "Going to execute commit on graph.";
115     private static final String GOING_TO_EXECUTE_ROLLBACK_ON_GRAPH = "Going to execute rollback on graph.";
116     private static final String FAILED_TO_ASSOCIATE_RESOURCE_TO_PROPERTY_IN_GRAPH_STATUS_IS = "Failed to associate resource {} to property {} in graph. status is {}";
117     private static final String AFTER_ADDING_PROPERTY_TO_GRAPH = "After adding property to graph {}";
118     private static final String BEFORE_ADDING_PROPERTY_TO_GRAPH = "Before adding property to graph {}";
119     private static final String THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID = "The value {} of property from type {} is invalid";
120     private static final String PROPERTY = "Property";
121     private static final String UPDATE_DATA_TYPE = "UpdateDataType";
122     private static final Logger log = Logger.getLogger(PropertyOperation.class.getName());
123     private final DerivedFromOperation derivedFromOperation;
124     private DataTypeOperation dataTypeOperation;
125
126     @Autowired
127     public PropertyOperation(final HealingJanusGraphGenericDao janusGraphGenericDao, final DerivedFromOperation derivedFromOperation) {
128         this.janusGraphGenericDao = janusGraphGenericDao;
129         this.derivedFromOperation = derivedFromOperation;
130     }
131
132     //circular dependency DataTypeOperation->ModelOperation->ModelElementOperation->PropertyOperation
133     @Autowired
134     public void setDataTypeOperation(DataTypeOperation dataTypeOperation) {
135         this.dataTypeOperation = dataTypeOperation;
136     }
137
138     public PropertyDefinition convertPropertyDataToPropertyDefinition(PropertyData propertyDataResult, String propertyName, String resourceId) {
139         log.debug("The object returned after create property is {}", propertyDataResult);
140         PropertyDefinition propertyDefResult = new PropertyDefinition(propertyDataResult.getPropertyDataDefinition());
141         propertyDefResult.setConstraints(convertConstraints(propertyDataResult.getConstraints()));
142         propertyDefResult.setName(propertyName);
143         return propertyDefResult;
144     }
145
146     public Either<PropertyData, StorageOperationStatus> addProperty(String propertyName, PropertyDefinition propertyDefinition, String resourceId) {
147         Either<PropertyData, JanusGraphOperationStatus> either = addPropertyToGraph(propertyName, propertyDefinition, resourceId);
148         if (either.isRight()) {
149             StorageOperationStatus storageStatus = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(either.right().value());
150             return Either.right(storageStatus);
151         }
152         return Either.left(either.left().value());
153     }
154
155     /**
156      * @param propertyDefinition
157      * @return
158      */
159     @Override
160     public StorageOperationStatus validateAndUpdateProperty(IComplexDefaultValue propertyDefinition, Map<String, DataTypeDefinition> dataTypes) {
161         log.trace("Going to validate property type and value. {}", propertyDefinition);
162         String propertyType = propertyDefinition.getType();
163         String value = propertyDefinition.getDefaultValue();
164         ToscaPropertyType type = getType(propertyType);
165         if (type == null) {
166             DataTypeDefinition dataTypeDefinition = dataTypes.get(propertyType);
167             if (dataTypeDefinition == null) {
168                 log.debug("The type {} of property cannot be found.", propertyType);
169                 return StorageOperationStatus.INVALID_TYPE;
170             }
171             return validateAndUpdateComplexValue(propertyDefinition, propertyType, value, dataTypeDefinition, dataTypes);
172         }
173         String innerType = null;
174         Either<String, JanusGraphOperationStatus> checkInnerType = getInnerType(type, propertyDefinition::getSchema);
175         if (checkInnerType.isRight()) {
176             return StorageOperationStatus.INVALID_TYPE;
177         }
178         innerType = checkInnerType.left().value();
179         log.trace("After validating property type {}", propertyType);
180         boolean isValidProperty = isValidValue(type, value, innerType, dataTypes);
181         if (!isValidProperty) {
182             log.info(THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID, value, type);
183             return StorageOperationStatus.INVALID_VALUE;
184         }
185         PropertyValueConverter converter = type.getConverter();
186         if (isEmptyValue(value)) {
187             log.debug("Default value was not sent for property {}. Set default value to {}", propertyDefinition.getName(), EMPTY_VALUE);
188             propertyDefinition.setDefaultValue(EMPTY_VALUE);
189         } else if (!isEmptyValue(value)) {
190             String convertedValue = converter.convert(value, innerType, dataTypes);
191             propertyDefinition.setDefaultValue(convertedValue);
192         }
193         return StorageOperationStatus.OK;
194     }
195
196     public Either<PropertyData, JanusGraphOperationStatus> addPropertyToGraph(String propertyName, PropertyDefinition propertyDefinition,
197                                                                               String resourceId) {
198         ResourceMetadataData resourceData = new ResourceMetadataData();
199         resourceData.getMetadataDataDefinition().setUniqueId(resourceId);
200         List<PropertyConstraint> constraints = propertyDefinition.getConstraints();
201         propertyDefinition.setUniqueId(UniqueIdBuilder.buildComponentPropertyUniqueId(resourceId, propertyName));
202         PropertyData propertyData = new PropertyData(propertyDefinition, convertConstraintsToString(constraints));
203         log.debug(BEFORE_ADDING_PROPERTY_TO_GRAPH, propertyData);
204         Either<PropertyData, JanusGraphOperationStatus> createNodeResult = janusGraphGenericDao.createNode(propertyData, PropertyData.class);
205         log.debug(AFTER_ADDING_PROPERTY_TO_GRAPH, propertyData);
206         if (createNodeResult.isRight()) {
207             JanusGraphOperationStatus operationStatus = createNodeResult.right().value();
208             log.error("Failed to add property {} to graph. status is {}", propertyName, operationStatus);
209             return Either.right(operationStatus);
210         }
211         Map<String, Object> props = new HashMap<>();
212         props.put(GraphPropertiesDictionary.NAME.getProperty(), propertyName);
213         Either<GraphRelation, JanusGraphOperationStatus> createRelResult = janusGraphGenericDao
214             .createRelation(resourceData, propertyData, GraphEdgeLabels.PROPERTY, props);
215         if (createRelResult.isRight()) {
216             JanusGraphOperationStatus operationStatus = createNodeResult.right().value();
217             log.error(FAILED_TO_ASSOCIATE_RESOURCE_TO_PROPERTY_IN_GRAPH_STATUS_IS, resourceId, propertyName, operationStatus);
218             return Either.right(operationStatus);
219         }
220         return Either.left(createNodeResult.left().value());
221     }
222
223     public JanusGraphOperationStatus addPropertyToGraphByVertex(JanusGraphVertex metadataVertex, String propertyName,
224                                                                 PropertyDefinition propertyDefinition, String resourceId) {
225         List<PropertyConstraint> constraints = propertyDefinition.getConstraints();
226         propertyDefinition.setUniqueId(UniqueIdBuilder.buildComponentPropertyUniqueId(resourceId, propertyName));
227         PropertyData propertyData = new PropertyData(propertyDefinition, convertConstraintsToString(constraints));
228         log.debug(BEFORE_ADDING_PROPERTY_TO_GRAPH, propertyData);
229         Either<JanusGraphVertex, JanusGraphOperationStatus> createNodeResult = janusGraphGenericDao.createNode(propertyData);
230         log.debug(AFTER_ADDING_PROPERTY_TO_GRAPH, propertyData);
231         if (createNodeResult.isRight()) {
232             JanusGraphOperationStatus operationStatus = createNodeResult.right().value();
233             log.error("Failed to add property {} to graph. status is ", propertyName, operationStatus);
234             return operationStatus;
235         }
236         Map<String, Object> props = new HashMap<>();
237         props.put(GraphPropertiesDictionary.NAME.getProperty(), propertyName);
238         JanusGraphVertex propertyVertex = createNodeResult.left().value();
239         JanusGraphOperationStatus createRelResult = janusGraphGenericDao.createEdge(metadataVertex, propertyVertex, GraphEdgeLabels.PROPERTY, props);
240         if (!createRelResult.equals(JanusGraphOperationStatus.OK)) {
241             log.error(FAILED_TO_ASSOCIATE_RESOURCE_TO_PROPERTY_IN_GRAPH_STATUS_IS, resourceId, propertyName, createRelResult);
242             return createRelResult;
243         }
244         return createRelResult;
245     }
246
247     public JanusGraphGenericDao getJanusGraphGenericDao() {
248         return janusGraphGenericDao;
249     }
250
251     /**
252      * FOR TEST ONLY
253      *
254      * @param janusGraphGenericDao
255      */
256     public void setJanusGraphGenericDao(HealingJanusGraphGenericDao janusGraphGenericDao) {
257         this.janusGraphGenericDao = janusGraphGenericDao;
258     }
259
260     public Either<PropertyData, JanusGraphOperationStatus> deletePropertyFromGraph(String propertyId) {
261         log.debug("Before deleting property from graph {}", propertyId);
262         return janusGraphGenericDao.deleteNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Property), propertyId, PropertyData.class);
263     }
264
265     public Either<PropertyData, StorageOperationStatus> updateProperty(String propertyId, PropertyDefinition newPropertyDefinition,
266                                                                        Map<String, DataTypeDefinition> dataTypes) {
267         StorageOperationStatus validateAndUpdateProperty = validateAndUpdateProperty(newPropertyDefinition, dataTypes);
268         if (validateAndUpdateProperty != StorageOperationStatus.OK) {
269             return Either.right(validateAndUpdateProperty);
270         }
271         Either<PropertyData, JanusGraphOperationStatus> either = updatePropertyFromGraph(propertyId, newPropertyDefinition);
272         if (either.isRight()) {
273             StorageOperationStatus storageStatus = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(either.right().value());
274             return Either.right(storageStatus);
275         }
276         return Either.left(either.left().value());
277     }
278
279     public Either<PropertyData, JanusGraphOperationStatus> updatePropertyFromGraph(String propertyId, PropertyDefinition propertyDefinition) {
280         if (log.isDebugEnabled()) {
281             log.debug("Before updating property on graph {}", propertyId);
282         }
283         // get the original property data
284         Either<PropertyData, JanusGraphOperationStatus> statusProperty = janusGraphGenericDao
285             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Property), propertyId, PropertyData.class);
286         if (statusProperty.isRight()) {
287             log.debug("Problem while get property with id {}. Reason - {}", propertyId, statusProperty.right().value().name());
288             return Either.right(statusProperty.right().value());
289         }
290         PropertyData orgPropertyData = statusProperty.left().value();
291         PropertyDataDefinition orgPropertyDataDefinition = orgPropertyData.getPropertyDataDefinition();
292         // create new property data to update
293         PropertyData newPropertyData = new PropertyData();
294         newPropertyData.setPropertyDataDefinition(propertyDefinition);
295         PropertyDataDefinition newPropertyDataDefinition = newPropertyData.getPropertyDataDefinition();
296         // update the original property data with new values
297         if (orgPropertyDataDefinition.getDefaultValue() == null) {
298             orgPropertyDataDefinition.setDefaultValue(newPropertyDataDefinition.getDefaultValue());
299         } else {
300             if (!orgPropertyDataDefinition.getDefaultValue().equals(newPropertyDataDefinition.getDefaultValue())) {
301                 orgPropertyDataDefinition.setDefaultValue(newPropertyDataDefinition.getDefaultValue());
302             }
303         }
304         if (orgPropertyDataDefinition.getDescription() == null) {
305             orgPropertyDataDefinition.setDescription(newPropertyDataDefinition.getDescription());
306         } else {
307             if (!orgPropertyDataDefinition.getDescription().equals(newPropertyDataDefinition.getDescription())) {
308                 orgPropertyDataDefinition.setDescription(newPropertyDataDefinition.getDescription());
309             }
310         }
311         if (!orgPropertyDataDefinition.getType().equals(newPropertyDataDefinition.getType())) {
312             orgPropertyDataDefinition.setType(newPropertyDataDefinition.getType());
313         }
314         if (newPropertyData.getConstraints() != null) {
315             orgPropertyData.setConstraints(newPropertyData.getConstraints());
316         }
317         orgPropertyDataDefinition.setSchema(newPropertyDataDefinition.getSchema());
318         return janusGraphGenericDao.updateNode(orgPropertyData, PropertyData.class);
319     }
320
321     public Either<PropertyData, JanusGraphOperationStatus> addPropertyToNodeType(String propertyName, PropertyDefinition propertyDefinition,
322                                                                                  NodeTypeEnum nodeType, String uniqueId) {
323         List<PropertyConstraint> constraints = propertyDefinition.getConstraints();
324         propertyDefinition.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(uniqueId, propertyName));
325         PropertyData propertyData = new PropertyData(propertyDefinition, convertConstraintsToString(constraints));
326         if (log.isDebugEnabled()) {
327             log.debug(BEFORE_ADDING_PROPERTY_TO_GRAPH, propertyData);
328         }
329         Either<PropertyData, JanusGraphOperationStatus> createNodeResult = janusGraphGenericDao.createNode(propertyData, PropertyData.class);
330         if (log.isDebugEnabled()) {
331             log.debug(AFTER_ADDING_PROPERTY_TO_GRAPH, propertyData);
332         }
333         if (createNodeResult.isRight()) {
334             JanusGraphOperationStatus operationStatus = createNodeResult.right().value();
335             log.error("Failed to add property {} to graph. status is {}", propertyName, operationStatus);
336             return Either.right(operationStatus);
337         }
338         Map<String, Object> props = new HashMap<>();
339         props.put(GraphPropertiesDictionary.NAME.getProperty(), propertyName);
340         UniqueIdData uniqueIdData = new UniqueIdData(nodeType, uniqueId);
341         log.debug("Before associating {} to property {}", uniqueIdData, propertyName);
342         Either<GraphRelation, JanusGraphOperationStatus> createRelResult = janusGraphGenericDao
343             .createRelation(uniqueIdData, propertyData, GraphEdgeLabels.PROPERTY, props);
344         if (createRelResult.isRight()) {
345             JanusGraphOperationStatus operationStatus = createNodeResult.right().value();
346             log.error(FAILED_TO_ASSOCIATE_RESOURCE_TO_PROPERTY_IN_GRAPH_STATUS_IS, uniqueId, propertyName, operationStatus);
347             return Either.right(operationStatus);
348         }
349         return Either.left(createNodeResult.left().value());
350     }
351
352     public Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> findPropertiesOfNode(NodeTypeEnum nodeType, String uniqueId) {
353         Map<String, PropertyDefinition> resourceProps = new HashMap<>();
354         Either<List<ImmutablePair<PropertyData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
355             .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(nodeType), uniqueId, GraphEdgeLabels.PROPERTY, NodeTypeEnum.Property,
356                 PropertyData.class);
357         if (childrenNodes.isRight()) {
358             JanusGraphOperationStatus operationStatus = childrenNodes.right().value();
359             return Either.right(operationStatus);
360         }
361         List<ImmutablePair<PropertyData, GraphEdge>> values = childrenNodes.left().value();
362         if (values != null) {
363             for (ImmutablePair<PropertyData, GraphEdge> immutablePair : values) {
364                 GraphEdge edge = immutablePair.getValue();
365                 String propertyName = (String) edge.getProperties().get(GraphPropertiesDictionary.NAME.getProperty());
366                 log.debug("Property {} is associated to node {}", propertyName, uniqueId);
367                 PropertyData propertyData = immutablePair.getKey();
368                 PropertyDefinition propertyDefinition = this.convertPropertyDataToPropertyDefinition(propertyData, propertyName, uniqueId);
369                 resourceProps.put(propertyName, propertyDefinition);
370             }
371         }
372         log.debug("The properties associated to node {} are {}", uniqueId, resourceProps);
373         return Either.left(resourceProps);
374     }
375
376     public Either<Map<String, PropertyDefinition>, StorageOperationStatus> deletePropertiesAssociatedToNode(NodeTypeEnum nodeType, String uniqueId) {
377         return deleteAllPropertiesAssociatedToNode(nodeType, uniqueId).right()
378             .bind(err -> err == StorageOperationStatus.OK ? Either.left(Collections.emptyMap()) : Either.right(err));
379     }
380
381     public Either<Map<String, PropertyData>, JanusGraphOperationStatus> mergePropertiesAssociatedToNode(NodeTypeEnum nodeType, String uniqueId,
382                                                                                                         Map<String, PropertyDefinition> newProperties) {
383         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> oldPropertiesRes = findPropertiesOfNode(nodeType, uniqueId);
384         Map<String, PropertyDefinition> reallyNewProperties;
385         Map<String, PropertyData> unchangedPropsData;
386         if (oldPropertiesRes.isRight()) {
387             JanusGraphOperationStatus err = oldPropertiesRes.right().value();
388             if (err == JanusGraphOperationStatus.NOT_FOUND) {
389                 reallyNewProperties = newProperties;
390                 unchangedPropsData = Collections.emptyMap();
391             } else {
392                 return Either.right(err);
393             }
394         } else {
395             Map<String, PropertyDefinition> oldProperties = oldPropertiesRes.left().value();
396             reallyNewProperties = collectReallyNewProperties(newProperties, oldProperties);
397             for (Entry<String, PropertyDefinition> oldEntry : oldProperties.entrySet()) {
398                 String key = oldEntry.getKey();
399                 PropertyDefinition newPropDef = newProperties != null ? newProperties.get(key) : null;
400                 PropertyDefinition oldPropDef = oldEntry.getValue();
401                 JanusGraphOperationStatus status = updateOldProperty(newPropDef, oldPropDef);
402                 if (status != JanusGraphOperationStatus.OK) {
403                     return Either.right(status);
404                 }
405             }
406             unchangedPropsData = oldProperties.entrySet().stream()
407                 .collect(Collectors.toMap(Entry::getKey, e -> new PropertyData(e.getValue(), null)));
408         }
409         // add other properties
410         return addPropertiesToElementType(nodeType, uniqueId, reallyNewProperties, unchangedPropsData);
411     }
412
413     /**
414      * @param newProperties
415      * @param oldProperties
416      * @return
417      */
418     private Map<String, PropertyDefinition> collectReallyNewProperties(Map<String, PropertyDefinition> newProperties,
419                                                                        Map<String, PropertyDefinition> oldProperties) {
420         return newProperties != null ? newProperties.entrySet().stream().filter(entry -> !oldProperties.containsKey(entry.getKey()))
421             .collect(Collectors.toMap(Entry::getKey, Entry::getValue)) : null;
422     }
423
424     /**
425      * @param newPropDef
426      * @param oldPropDef
427      */
428     private JanusGraphOperationStatus updateOldProperty(PropertyDefinition newPropDef, PropertyDefinition oldPropDef) {
429         if (!isUpdateAllowed(newPropDef, oldPropDef)) {
430             return JanusGraphOperationStatus.MATCH_NOT_FOUND;
431         }
432         if (isUpdateRequired(newPropDef, oldPropDef)) {
433             modifyOldPropByNewOne(newPropDef, oldPropDef);
434             List<PropertyConstraint> constraints = oldPropDef.getConstraints();
435             PropertyData node = new PropertyData(oldPropDef, convertConstraintsToString(constraints));
436             Either<PropertyData, JanusGraphOperationStatus> updateResult = janusGraphGenericDao.updateNode(node, PropertyData.class);
437             if (updateResult.isRight()) {
438                 return updateResult.right().value();
439             }
440         }
441         return JanusGraphOperationStatus.OK;
442     }
443
444     /**
445      * @param newPropDef
446      * @param oldPropDef
447      */
448     private boolean isUpdateAllowed(PropertyDefinition newPropDef, PropertyDefinition oldPropDef) {
449         if (newPropDef == null) {
450             log.error("#mergePropertiesAssociatedToNode - Failed due attempt to delete the property with id {}", oldPropDef.getUniqueId());
451             return false;
452         }
453         // If the property type is missing it's something that we could want to fix
454         if (oldPropDef.getType() != null && !oldPropDef.getType().equals(newPropDef.getType())) {
455             log.error("#mergePropertiesAssociatedToNode - Failed due attempt to change type of the property with id {}", oldPropDef.getUniqueId());
456             return false;
457         }
458         return true;
459     }
460
461     /**
462      * Update only fields which modification is permitted.
463      *
464      * @param newPropDef
465      * @param oldPropDef
466      */
467     private void modifyOldPropByNewOne(PropertyDefinition newPropDef, PropertyDefinition oldPropDef) {
468         oldPropDef.setDefaultValue(newPropDef.getDefaultValue());
469         oldPropDef.setDescription(newPropDef.getDescription());
470         oldPropDef.setRequired(newPropDef.isRequired());
471         // Type is updated to fix possible null type issue in janusGraph DB
472         oldPropDef.setType(newPropDef.getType());
473     }
474
475     private boolean isUpdateRequired(PropertyDefinition newPropDef, PropertyDefinition oldPropDef) {
476         return !StringUtils.equals(oldPropDef.getDefaultValue(), newPropDef.getDefaultValue()) || !StringUtils
477             .equals(oldPropDef.getDescription(), newPropDef.getDescription()) || oldPropDef.isRequired() != newPropDef.isRequired();
478     }
479
480     /**
481      * Adds newProperties and returns in case of success (left part of Either) map of all properties i. e. added ones and contained in
482      * unchangedPropsData
483      *
484      * @param nodeType
485      * @param uniqueId
486      * @param newProperties
487      * @param unchangedPropsData
488      * @return
489      */
490     private Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToElementType(NodeTypeEnum nodeType, String uniqueId,
491                                                                                                     Map<String, PropertyDefinition> newProperties,
492                                                                                                     Map<String, PropertyData> unchangedPropsData) {
493         return addPropertiesToElementType(uniqueId, nodeType, newProperties).left().map(m -> {
494             m.putAll(unchangedPropsData);
495             return m;
496         });
497     }
498
499     public Either<Map<String, PropertyDefinition>, StorageOperationStatus> deleteAllPropertiesAssociatedToNode(NodeTypeEnum nodeType,
500                                                                                                                String uniqueId) {
501         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesOfNodeRes = findPropertiesOfNode(nodeType, uniqueId);
502         if (propertiesOfNodeRes.isRight()) {
503             JanusGraphOperationStatus status = propertiesOfNodeRes.right().value();
504             if (status == JanusGraphOperationStatus.NOT_FOUND) {
505                 return Either.right(StorageOperationStatus.OK);
506             }
507             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
508         }
509         Map<String, PropertyDefinition> value = propertiesOfNodeRes.left().value();
510         for (PropertyDefinition propertyDefinition : value.values()) {
511             String propertyUid = propertyDefinition.getUniqueId();
512             Either<PropertyData, JanusGraphOperationStatus> deletePropertyRes = deletePropertyFromGraph(propertyUid);
513             if (deletePropertyRes.isRight()) {
514                 log.error("Failed to delete property with id {}", propertyUid);
515                 JanusGraphOperationStatus status = deletePropertyRes.right().value();
516                 if (status == JanusGraphOperationStatus.NOT_FOUND) {
517                     status = JanusGraphOperationStatus.INVALID_ID;
518                 }
519                 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
520             }
521         }
522         log.debug("The properties deleted from node {} are {}", uniqueId, value);
523         return Either.left(value);
524     }
525
526     /**
527      * Checks existence of a property with the same name belonging to the same resource or existence of property with the same name and different type
528      * (including derived from hierarchy)
529      *
530      * @param properties
531      * @param resourceUid
532      * @param propertyName
533      * @param propertyType
534      * @return
535      */
536     public boolean isPropertyExist(List<PropertyDefinition> properties, String resourceUid, String propertyName, String propertyType) {
537         boolean result = false;
538         if (!CollectionUtils.isEmpty(properties)) {
539             for (PropertyDefinition propertyDefinition : properties) {
540                 if (propertyDefinition.getName().equals(propertyName) && (propertyDefinition.getParentUniqueId().equals(resourceUid)
541                     || !propertyDefinition.getType().equals(propertyType))) {
542                     result = true;
543                     break;
544                 }
545             }
546         }
547         return result;
548     }
549
550     public ImmutablePair<String, Boolean> validateAndUpdateRules(String propertyType, List<PropertyRule> rules, String innerType,
551                                                                  Map<String, DataTypeDefinition> dataTypes, boolean isValidate) {
552         if (rules == null || rules.isEmpty()) {
553             return new ImmutablePair<>(null, true);
554         }
555         for (PropertyRule rule : rules) {
556             String value = rule.getValue();
557             Either<Object, Boolean> updateResult = validateAndUpdatePropertyValue(propertyType, value, isValidate, innerType, dataTypes);
558             if (updateResult.isRight()) {
559                 Boolean status = updateResult.right().value();
560                 if (!status) {
561                     return new ImmutablePair<>(value, status);
562                 }
563             } else {
564                 String newValue = null;
565                 Object object = updateResult.left().value();
566                 if (object != null) {
567                     newValue = object.toString();
568                 }
569                 rule.setValue(newValue);
570             }
571         }
572         return new ImmutablePair<>(null, true);
573     }
574
575     public void addRulesToNewPropertyValue(PropertyValueData propertyValueData, ComponentInstanceProperty resourceInstanceProperty,
576                                            String resourceInstanceId) {
577         List<PropertyRule> rules = resourceInstanceProperty.getRules();
578         if (rules == null) {
579             PropertyRule propertyRule = buildRuleFromPath(propertyValueData, resourceInstanceProperty, resourceInstanceId);
580             rules = new ArrayList<>();
581             rules.add(propertyRule);
582         } else {
583             rules = sortRules(rules);
584         }
585         propertyValueData.setRules(rules);
586     }
587
588     private PropertyRule buildRuleFromPath(PropertyValueData propertyValueData, ComponentInstanceProperty resourceInstanceProperty,
589                                            String resourceInstanceId) {
590         List<String> path = resourceInstanceProperty.getPath();
591         // FOR BC. Since old Property values on VFC/VF does not have rules on
592
593         // graph.
594
595         // Update could be done on one level only, thus we can use this
596
597         // operation to avoid migration.
598         if (path == null || path.isEmpty()) {
599             path = new ArrayList<>();
600             path.add(resourceInstanceId);
601         }
602         PropertyRule propertyRule = new PropertyRule();
603         propertyRule.setRule(path);
604         propertyRule.setValue(propertyValueData.getValue());
605         return propertyRule;
606     }
607
608     private List<PropertyRule> sortRules(List<PropertyRule> rules) {
609         // TODO: sort the rules by size and binary representation.
610
611         // (x, y, .+) --> 110 6 priority 1
612
613         // (x, .+, z) --> 101 5 priority 2
614         return rules;
615     }
616
617     public ImmutablePair<JanusGraphOperationStatus, String> findPropertyValue(String resourceInstanceId, String propertyId) {
618         log.debug("Going to check whether the property {} already added to resource instance {}", propertyId, resourceInstanceId);
619         Either<List<ComponentInstanceProperty>, JanusGraphOperationStatus> getAllRes = this
620             .getAllPropertiesOfResourceInstanceOnlyPropertyDefId(resourceInstanceId);
621         if (getAllRes.isRight()) {
622             JanusGraphOperationStatus status = getAllRes.right().value();
623             log.trace("After fetching all properties of resource instance {}. Status is {}", resourceInstanceId, status);
624             return new ImmutablePair<>(status, null);
625         }
626         List<ComponentInstanceProperty> list = getAllRes.left().value();
627         if (list != null) {
628             for (ComponentInstanceProperty instanceProperty : list) {
629                 String propertyUniqueId = instanceProperty.getUniqueId();
630                 String valueUniqueUid = instanceProperty.getValueUniqueUid();
631                 log.trace("Go over property {} under resource instance {}. valueUniqueId = {}", propertyUniqueId, resourceInstanceId, valueUniqueUid);
632                 if (propertyId.equals(propertyUniqueId) && valueUniqueUid != null) {
633                     log.debug("The property {} already created under resource instance {}", propertyId, resourceInstanceId);
634                     return new ImmutablePair<>(JanusGraphOperationStatus.ALREADY_EXIST, valueUniqueUid);
635                 }
636             }
637         }
638         return new ImmutablePair<>(JanusGraphOperationStatus.NOT_FOUND, null);
639     }
640
641     public void updateRulesInPropertyValue(PropertyValueData propertyValueData, ComponentInstanceProperty resourceInstanceProperty,
642                                            String resourceInstanceId) {
643         List<PropertyRule> currentRules = propertyValueData.getRules();
644         List<PropertyRule> rules = resourceInstanceProperty.getRules();
645         // if rules are not supported.
646         if (rules == null) {
647             PropertyRule propertyRule = buildRuleFromPath(propertyValueData, resourceInstanceProperty, resourceInstanceId);
648             rules = new ArrayList<>();
649             rules.add(propertyRule);
650             if (currentRules != null) {
651                 rules = mergeRules(currentRules, rules);
652             }
653         } else {
654             // Full mode. all rules are sent in update operation.
655             rules = sortRules(rules);
656         }
657         propertyValueData.setRules(rules);
658     }
659
660     private List<PropertyRule> mergeRules(List<PropertyRule> currentRules, List<PropertyRule> newRules) {
661         List<PropertyRule> mergedRules = new ArrayList<>();
662         if (newRules == null || newRules.isEmpty()) {
663             return currentRules;
664         }
665         for (PropertyRule rule : currentRules) {
666             PropertyRule propertyRule = new PropertyRule(rule.getRule(), rule.getValue());
667             mergedRules.add(propertyRule);
668         }
669         for (PropertyRule rule : newRules) {
670             PropertyRule foundRule = findRuleInList(rule, mergedRules);
671             if (foundRule != null) {
672                 foundRule.setValue(rule.getValue());
673             } else {
674                 mergedRules.add(rule);
675             }
676         }
677         return mergedRules;
678     }
679
680     private PropertyRule findRuleInList(PropertyRule rule, List<PropertyRule> rules) {
681         if (rules == null || rules.isEmpty() || rule.getRule() == null || rule.getRule().isEmpty()) {
682             return null;
683         }
684         PropertyRule foundRule = null;
685         for (PropertyRule propertyRule : rules) {
686             if (rule.getRuleSize() != propertyRule.getRuleSize()) {
687                 continue;
688             }
689             boolean equals = propertyRule.compareRule(rule);
690             if (equals) {
691                 foundRule = propertyRule;
692                 break;
693             }
694         }
695         return foundRule;
696     }
697
698     /**
699      * return all properties associated to resource instance. The result does contains the property unique id but not its type, default value...
700      *
701      * @param resourceInstanceUid
702      * @return
703      */
704     public Either<List<ComponentInstanceProperty>, JanusGraphOperationStatus> getAllPropertiesOfResourceInstanceOnlyPropertyDefId(
705         String resourceInstanceUid) {
706         return getAllPropertiesOfResourceInstanceOnlyPropertyDefId(resourceInstanceUid, NodeTypeEnum.ResourceInstance);
707     }
708
709     public Either<PropertyValueData, JanusGraphOperationStatus> removePropertyOfResourceInstance(String propertyValueUid, String resourceInstanceId) {
710         Either<ComponentInstanceData, JanusGraphOperationStatus> findResInstanceRes = janusGraphGenericDao
711             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceInstance), resourceInstanceId, ComponentInstanceData.class);
712         if (findResInstanceRes.isRight()) {
713             JanusGraphOperationStatus status = findResInstanceRes.right().value();
714             if (status == JanusGraphOperationStatus.NOT_FOUND) {
715                 status = JanusGraphOperationStatus.INVALID_ID;
716             }
717             return Either.right(status);
718         }
719         Either<PropertyValueData, JanusGraphOperationStatus> findPropertyDefRes = janusGraphGenericDao
720             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.PropertyValue), propertyValueUid, PropertyValueData.class);
721         if (findPropertyDefRes.isRight()) {
722             JanusGraphOperationStatus status = findPropertyDefRes.right().value();
723             if (status == JanusGraphOperationStatus.NOT_FOUND) {
724                 status = JanusGraphOperationStatus.INVALID_ID;
725             }
726             return Either.right(status);
727         }
728         Either<GraphRelation, JanusGraphOperationStatus> relation = janusGraphGenericDao
729             .getRelation(findResInstanceRes.left().value(), findPropertyDefRes.left().value(), GraphEdgeLabels.PROPERTY_VALUE);
730         if (relation.isRight()) {
731             // TODO: add error in case of error
732             JanusGraphOperationStatus status = relation.right().value();
733             if (status == JanusGraphOperationStatus.NOT_FOUND) {
734                 status = JanusGraphOperationStatus.INVALID_ID;
735             }
736             return Either.right(status);
737         }
738         Either<PropertyValueData, JanusGraphOperationStatus> deleteNode = janusGraphGenericDao
739             .deleteNode(findPropertyDefRes.left().value(), PropertyValueData.class);
740         if (deleteNode.isRight()) {
741             return Either.right(deleteNode.right().value());
742         }
743         PropertyValueData value = deleteNode.left().value();
744         return Either.left(value);
745     }
746
747     public Either<ComponentInstanceProperty, StorageOperationStatus> removePropertyValueFromResourceInstance(String propertyValueUid,
748                                                                                                              String resourceInstanceId,
749                                                                                                              boolean inTransaction) {
750         Either<ComponentInstanceProperty, StorageOperationStatus> result = null;
751         try {
752             Either<PropertyValueData, JanusGraphOperationStatus> eitherStatus = this
753                 .removePropertyOfResourceInstance(propertyValueUid, resourceInstanceId);
754             if (eitherStatus.isRight()) {
755                 log.error("Failed to remove property value {} from resource instance {} in Graph. status is {}", propertyValueUid, resourceInstanceId,
756                     eitherStatus.right().value().name());
757                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(eitherStatus.right().value()));
758                 return result;
759             } else {
760                 PropertyValueData propertyValueData = eitherStatus.left().value();
761                 ComponentInstanceProperty propertyValueResult = new ComponentInstanceProperty();
762                 propertyValueResult.setUniqueId(resourceInstanceId);
763                 propertyValueResult.setValue(propertyValueData.getValue());
764                 log.debug("The returned ResourceInstanceProperty is  {}", propertyValueResult);
765                 result = Either.left(propertyValueResult);
766                 return result;
767             }
768         } finally {
769             if (!inTransaction) {
770                 if (result == null || result.isRight()) {
771                     log.error(GOING_TO_EXECUTE_ROLLBACK_ON_GRAPH);
772                     janusGraphGenericDao.rollback();
773                 } else {
774                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_GRAPH);
775                     janusGraphGenericDao.commit();
776                 }
777             }
778         }
779     }
780
781     public ComponentInstanceProperty buildResourceInstanceProperty(PropertyValueData propertyValueData,
782                                                                    ComponentInstanceProperty resourceInstanceProperty) {
783         String value = propertyValueData.getValue();
784         String uid = propertyValueData.getUniqueId();
785         ComponentInstanceProperty instanceProperty = new ComponentInstanceProperty(resourceInstanceProperty, value, uid);
786         instanceProperty.setPath(resourceInstanceProperty.getPath());
787         return instanceProperty;
788     }
789
790     @Override
791     public boolean isPropertyDefaultValueValid(IComplexDefaultValue propertyDefinition, Map<String, DataTypeDefinition> dataTypes) {
792         if (propertyDefinition == null) {
793             return false;
794         }
795         String innerType = null;
796         String propertyType = propertyDefinition.getType();
797         ToscaPropertyType type = getType(propertyType);
798         if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
799             SchemaDefinition def = propertyDefinition.getSchema();
800             if (def == null) {
801                 return false;
802             }
803             PropertyDataDefinition propDef = def.getProperty();
804             if (propDef == null) {
805                 return false;
806             }
807             innerType = propDef.getType();
808         }
809         String value = propertyDefinition.getDefaultValue();
810         if (type != null) {
811             return isValidValue(type, value, innerType, dataTypes);
812         } else {
813             log.trace("The given type {} is not a pre defined one.", propertyType);
814             DataTypeDefinition foundDt = dataTypes.get(propertyType);
815             if (foundDt != null) {
816                 return isValidComplexValue(foundDt, value, dataTypes);
817             } else {
818                 return false;
819             }
820         }
821     }
822
823     public boolean isPropertyTypeValid(final IComplexDefaultValue property, final String model) {
824         if (property == null) {
825             return false;
826         }
827         if (ToscaPropertyType.isValidType(property.getType()) == null) {
828             Either<Boolean, JanusGraphOperationStatus> definedInDataTypes = isDefinedInDataTypes(property.getType(), model);
829             if (definedInDataTypes.isRight()) {
830                 return false;
831             } else {
832                 Boolean isExist = definedInDataTypes.left().value();
833                 return isExist.booleanValue();
834             }
835         }
836         return true;
837     }
838     
839     public boolean isPropertyTypeValid(final IComplexDefaultValue property, final Map<String, DataTypeDefinition> dataTypes) {
840         if (property == null) {
841             return false;
842         }
843         return ToscaPropertyType.isValidType(property.getType()) != null || dataTypes.containsKey(property.getType());
844     }
845
846     @Override
847     public ImmutablePair<String, Boolean> isPropertyInnerTypeValid(IComplexDefaultValue property, Map<String, DataTypeDefinition> dataTypes) {
848         if (property == null) {
849             return new ImmutablePair<>(null, false);
850         }
851         SchemaDefinition schema;
852         PropertyDataDefinition innerProp;
853         String innerType = null;
854         if ((schema = property.getSchema()) != null) {
855             if ((innerProp = schema.getProperty()) != null) {
856                 innerType = innerProp.getType();
857             }
858         }
859         ToscaPropertyType innerToscaType = ToscaPropertyType.isValidType(innerType);
860         if (innerToscaType == null) {
861             DataTypeDefinition dataTypeDefinition = dataTypes.get(innerType);
862             if (dataTypeDefinition == null) {
863                 log.debug("The inner type {} is not a data type.", innerType);
864                 return new ImmutablePair<>(innerType, false);
865             } else {
866                 log.debug("The inner type {} is a data type. Data type definition is {}", innerType, dataTypeDefinition);
867             }
868         }
869         return new ImmutablePair<>(innerType, true);
870     }
871
872     private boolean isValidComplexValue(DataTypeDefinition foundDt, String value, Map<String, DataTypeDefinition> dataTypes) {
873         ImmutablePair<JsonElement, Boolean> validateAndUpdate = dataTypeValidatorConverter.validateAndUpdate(value, foundDt, dataTypes);
874         log.trace("The result after validating complex value of type {} is {}", foundDt.getName(), validateAndUpdate);
875         return validateAndUpdate.right.booleanValue();
876     }
877
878     public Either<List<ComponentInstanceProperty>, JanusGraphOperationStatus> getAllPropertiesOfResourceInstanceOnlyPropertyDefId(
879         String resourceInstanceUid, NodeTypeEnum instanceNodeType) {
880         Either<JanusGraphVertex, JanusGraphOperationStatus> findResInstanceRes = janusGraphGenericDao
881             .getVertexByProperty(UniqueIdBuilder.getKeyByNodeType(instanceNodeType), resourceInstanceUid);
882         if (findResInstanceRes.isRight()) {
883             JanusGraphOperationStatus status = findResInstanceRes.right().value();
884             if (status == JanusGraphOperationStatus.NOT_FOUND) {
885                 status = JanusGraphOperationStatus.INVALID_ID;
886             }
887             return Either.right(status);
888         }
889         Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> propertyImplNodes = janusGraphGenericDao
890             .getChildrenVertecies(UniqueIdBuilder.getKeyByNodeType(instanceNodeType), resourceInstanceUid, GraphEdgeLabels.PROPERTY_VALUE);
891         if (propertyImplNodes.isRight()) {
892             JanusGraphOperationStatus status = propertyImplNodes.right().value();
893             return Either.right(status);
894         }
895         List<ImmutablePair<JanusGraphVertex, Edge>> list = propertyImplNodes.left().value();
896         if (list == null || list.isEmpty()) {
897             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
898         }
899         List<ComponentInstanceProperty> result = new ArrayList<>();
900         for (ImmutablePair<JanusGraphVertex, Edge> propertyValue : list) {
901             JanusGraphVertex propertyValueDataVertex = propertyValue.getLeft();
902             String propertyValueUid = (String) janusGraphGenericDao
903                 .getProperty(propertyValueDataVertex, GraphPropertiesDictionary.UNIQUE_ID.getProperty());
904             String value = (String) janusGraphGenericDao.getProperty(propertyValueDataVertex, GraphPropertiesDictionary.VALUE.getProperty());
905             ImmutablePair<JanusGraphVertex, Edge> propertyDefPair = janusGraphGenericDao
906                 .getChildVertex(propertyValueDataVertex, GraphEdgeLabels.PROPERTY_IMPL);
907             if (propertyDefPair == null) {
908                 return Either.right(JanusGraphOperationStatus.NOT_FOUND);
909             }
910             Map<String, Object> properties = janusGraphGenericDao.getProperties(propertyValueDataVertex);
911             PropertyValueData propertyValueData = GraphElementFactory
912                 .createElement(NodeTypeEnum.PropertyValue.getName(), GraphElementTypeEnum.Node, properties, PropertyValueData.class);
913             String propertyUniqueId = (String) janusGraphGenericDao
914                 .getProperty(propertyDefPair.left, GraphPropertiesDictionary.UNIQUE_ID.getProperty());
915             ComponentInstanceProperty resourceInstanceProperty = new ComponentInstanceProperty();
916             // set property original unique id
917             resourceInstanceProperty.setUniqueId(propertyUniqueId);
918             // set resource id
919
920             // TODO: esofer add resource id
921             resourceInstanceProperty.setParentUniqueId(null);
922             // set value
923             resourceInstanceProperty.setValue(value);
924             // set property value unique id
925             resourceInstanceProperty.setValueUniqueUid(propertyValueUid);
926             // set rules
927             resourceInstanceProperty.setRules(propertyValueData.getRules());
928             result.add(resourceInstanceProperty);
929         }
930         return Either.left(result);
931     }
932
933     /**
934      * Find the default value from the list of component instances. Start the search from the second component instance
935      *
936      * @param pathOfComponentInstances
937      * @param propertyUniqueId
938      * @param defaultValue
939      * @return
940      */
941     public Either<String, JanusGraphOperationStatus> findDefaultValueFromSecondPosition(List<String> pathOfComponentInstances,
942                                                                                         String propertyUniqueId, String defaultValue) {
943         log.trace("In find default value: path= {} propertyUniqId={} defaultValue= {}", pathOfComponentInstances, propertyUniqueId, defaultValue);
944         if (pathOfComponentInstances == null || pathOfComponentInstances.size() < 2) {
945             return Either.left(defaultValue);
946         }
947         String result = defaultValue;
948         for (int i = 1; i < pathOfComponentInstances.size(); i++) {
949             String compInstanceId = pathOfComponentInstances.get(i);
950             Either<List<ComponentInstanceProperty>, JanusGraphOperationStatus> propertyValuesResult = this
951                 .getAllPropertiesOfResourceInstanceOnlyPropertyDefId(compInstanceId, NodeTypeEnum.ResourceInstance);
952             log.trace("After fetching properties values of component instance {}. {}", compInstanceId, propertyValuesResult);
953             if (propertyValuesResult.isRight()) {
954                 JanusGraphOperationStatus status = propertyValuesResult.right().value();
955                 if (status != JanusGraphOperationStatus.NOT_FOUND) {
956                     return Either.right(status);
957                 } else {
958                     continue;
959                 }
960             }
961             ComponentInstanceProperty foundCompInstanceProperty = fetchByPropertyUid(propertyValuesResult.left().value(), propertyUniqueId);
962             log.trace("After finding the component instance property on{} . {}", compInstanceId, foundCompInstanceProperty);
963             if (foundCompInstanceProperty == null) {
964                 continue;
965             }
966             List<PropertyRule> rules = getOrBuildRulesIfNotExists(pathOfComponentInstances.size() - i, pathOfComponentInstances.get(i),
967                 foundCompInstanceProperty.getRules(), foundCompInstanceProperty.getValue());
968             log.trace("Rules of property {} on component instance {} are {}", propertyUniqueId, compInstanceId, rules);
969             PropertyRule matchedRule = findMatchRule(pathOfComponentInstances, i, rules);
970             log.trace("Match rule is {}", matchedRule);
971             if (matchedRule != null) {
972                 result = matchedRule.getValue();
973                 break;
974             }
975         }
976         return Either.left(result);
977     }
978
979     private ComponentInstanceProperty fetchByPropertyUid(List<ComponentInstanceProperty> list, String propertyUniqueId) {
980         ComponentInstanceProperty result = null;
981         if (list == null) {
982             return null;
983         }
984         for (ComponentInstanceProperty instProperty : list) {
985             if (instProperty.getUniqueId().equals(propertyUniqueId)) {
986                 result = instProperty;
987                 break;
988             }
989         }
990         return result;
991     }
992
993     private List<PropertyRule> getOrBuildRulesIfNotExists(int ruleSize, String compInstanceId, List<PropertyRule> rules, String value) {
994         if (rules != null) {
995             return rules;
996         }
997         rules = buildDefaultRule(compInstanceId, ruleSize, value);
998         return rules;
999     }
1000
1001     private List<PropertyRule> getRulesOfPropertyValue(int size, String instanceId, ComponentInstanceProperty componentInstanceProperty) {
1002         List<PropertyRule> rules = componentInstanceProperty.getRules();
1003         if (rules == null) {
1004             rules = buildDefaultRule(instanceId, size, componentInstanceProperty.getValue());
1005         }
1006         return rules;
1007     }
1008
1009     private List<PropertyRule> buildDefaultRule(String componentInstanceId, int size, String value) {
1010         List<PropertyRule> rules = new ArrayList<>();
1011         List<String> rule = new ArrayList<>();
1012         rule.add(componentInstanceId);
1013         for (int i = 0; i < size - 1; i++) {
1014             rule.add(PropertyRule.getRuleAnyMatch());
1015         }
1016         PropertyRule propertyRule = new PropertyRule(rule, value);
1017         rules.add(propertyRule);
1018         return rules;
1019     }
1020
1021     private PropertyRule findMatchRule(List<String> pathOfInstances, int level, List<PropertyRule> rules) {
1022         PropertyRule propertyRule = null;
1023         String stringForMatch = buildStringForMatch(pathOfInstances, level);
1024         String firstCompInstance = pathOfInstances.get(level);
1025         if (rules != null) {
1026             for (PropertyRule rule : rules) {
1027                 int ruleSize = rule.getRule().size();
1028                 // check the length of the rule equals to the length of the
1029
1030                 // instances path.
1031                 if (ruleSize != pathOfInstances.size() - level) {
1032                     continue;
1033                 }
1034                 // check that the rule starts with correct component instance id
1035                 if (!checkFirstItem(firstCompInstance, rule.getFirstToken())) {
1036                     continue;
1037                 }
1038                 String secondToken = rule.getToken(2);
1039                 if (secondToken != null && (secondToken.equals(PropertyRule.getForceAll()) || secondToken.equals(PropertyRule.getALL()))) {
1040                     propertyRule = rule;
1041                     break;
1042                 }
1043                 String patternStr = buildStringForMatch(rule.getRule(), 0);
1044                 Pattern pattern = Pattern.compile(patternStr);
1045                 Matcher matcher = pattern.matcher(stringForMatch);
1046                 if (matcher.matches()) {
1047                     if (log.isTraceEnabled()) {
1048                         log.trace("{} matches the rule {}", stringForMatch, patternStr);
1049                     }
1050                     propertyRule = rule;
1051                     break;
1052                 }
1053             }
1054         }
1055         return propertyRule;
1056     }
1057
1058     private boolean checkFirstItem(String left, String right) {
1059         if (left != null && left.equals(right)) {
1060             return true;
1061         }
1062         return false;
1063     }
1064
1065     private String buildStringForMatch(List<String> pathOfInstances, int level) {
1066         StringBuilder builder = new StringBuilder();
1067         for (int i = level; i < pathOfInstances.size(); i++) {
1068             builder.append(pathOfInstances.get(i));
1069             if (i < pathOfInstances.size() - 1) {
1070                 builder.append("#");
1071             }
1072         }
1073         return builder.toString();
1074     }
1075
1076     public void updatePropertyByBestMatch(String propertyUniqueId, ComponentInstanceProperty instanceProperty,
1077                                           Map<String, ComponentInstanceProperty> instanceIdToValue) {
1078         List<String> pathOfInstances = instanceProperty.getPath();
1079         int level = 0;
1080         int size = pathOfInstances.size();
1081         int numberOfMatches = 0;
1082         for (String instanceId : pathOfInstances) {
1083             ComponentInstanceProperty componentInstanceProperty = instanceIdToValue.get(instanceId);
1084             if (componentInstanceProperty != null) {
1085                 List<PropertyRule> rules = getRulesOfPropertyValue(size - level, instanceId, componentInstanceProperty);
1086                 // If it is the first level instance, then update valueUniuqeId
1087
1088                 // parameter in order to know on update that
1089
1090                 // we should update and not create new node on graph.
1091                 if (level == 0) {
1092                     instanceProperty.setValueUniqueUid(componentInstanceProperty.getValueUniqueUid());
1093                     instanceProperty.setRules(rules);
1094                 }
1095                 PropertyRule rule = findMatchRule(pathOfInstances, level, rules);
1096                 if (rule != null) {
1097                     numberOfMatches++;
1098                     String value = rule.getValue();
1099                     if (numberOfMatches == 1) {
1100                         instanceProperty.setValue(value);
1101                         if (log.isDebugEnabled()) {
1102                             log.debug("Set the value of property {} {} on path {} to be {}", propertyUniqueId, instanceProperty.getName(),
1103                                 pathOfInstances, value);
1104                         }
1105                     } else if (numberOfMatches == 2) {
1106                         // In case of another property value match, then use the
1107
1108                         // value to be the default value of the property.
1109                         instanceProperty.setDefaultValue(value);
1110                         if (log.isDebugEnabled()) {
1111                             log.debug("Set the default value of property {} {} on path {} to be {}", propertyUniqueId, instanceProperty.getName(),
1112                                 pathOfInstances, value);
1113                         }
1114                         break;
1115                     }
1116                 }
1117             }
1118             level++;
1119         }
1120     }
1121
1122     /**
1123      * Add data type to graph.
1124      * <p>
1125      * 1. Add data type node
1126      * <p>
1127      * 2. Add edge between the former node to its parent(if exists)
1128      * <p>
1129      * 3. Add property node and associate it to the node created at #1. (per property & if exists)
1130      *
1131      * @param dataTypeDefinition
1132      * @return
1133      */
1134     private Either<DataTypeData, JanusGraphOperationStatus> addDataTypeToGraph(DataTypeDefinition dataTypeDefinition) {
1135         log.debug("Got data type {}", dataTypeDefinition);
1136         String dtUniqueId = UniqueIdBuilder.buildDataTypeUid(dataTypeDefinition.getModel(), dataTypeDefinition.getName());
1137         DataTypeData dataTypeData = buildDataTypeData(dataTypeDefinition, dtUniqueId);
1138         log.debug("Before adding data type to graph. dataTypeData = {}", dataTypeData);
1139         Either<DataTypeData, JanusGraphOperationStatus> createDataTypeResult = janusGraphGenericDao.createNode(dataTypeData, DataTypeData.class);
1140         log.debug("After adding data type to graph. status is = {}", createDataTypeResult);
1141         if (createDataTypeResult.isRight()) {
1142             JanusGraphOperationStatus operationStatus = createDataTypeResult.right().value();
1143             log.debug("Failed to data type {} to graph. status is {}", dataTypeDefinition.getName(), operationStatus);
1144             BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError("AddDataType", NodeTypeEnum.DataType.getName());
1145             return Either.right(operationStatus);
1146         }
1147         DataTypeData resultCTD = createDataTypeResult.left().value();
1148         List<PropertyDefinition> properties = dataTypeDefinition.getProperties();
1149         Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToDataType = addPropertiesToDataType(resultCTD.getUniqueId(), dataTypeDefinition.getModel(),
1150             properties);
1151         if (addPropertiesToDataType.isRight()) {
1152             log.debug("Failed add properties {} to data type {}", properties, dataTypeDefinition.getName());
1153             return Either.right(addPropertiesToDataType.right().value());
1154         }
1155         
1156         final Either<GraphRelation, JanusGraphOperationStatus> modelRelationship = addDataTypeToModel(dataTypeDefinition);
1157         if (modelRelationship.isRight()) {
1158             return Either.right(modelRelationship.right().value());
1159         }        
1160         
1161         String derivedFrom = dataTypeDefinition.getDerivedFromName();
1162         if (derivedFrom != null) {
1163             final Either<DataTypeDefinition, JanusGraphOperationStatus> derivedFromDataType = getDataTypeByNameValidForModel(derivedFrom, dataTypeDefinition.getModel());
1164             if (derivedFromDataType.isRight()) {
1165                 return Either.right(derivedFromDataType.right().value());
1166             }
1167             
1168             log.debug("Before creating relation between data type {} to its parent {}", dtUniqueId, derivedFrom);
1169             UniqueIdData from = new UniqueIdData(NodeTypeEnum.DataType, dtUniqueId);
1170             final String deriveFromUid = derivedFromDataType.left().value().getUniqueId();
1171             UniqueIdData to = new UniqueIdData(NodeTypeEnum.DataType, deriveFromUid);
1172             Either<GraphRelation, JanusGraphOperationStatus> createRelation = janusGraphGenericDao
1173                 .createRelation(from, to, GraphEdgeLabels.DERIVED_FROM, null);
1174             log.debug("After create relation between capability type {} to its parent {}. status is {}", dtUniqueId, derivedFrom, createRelation);
1175             if (createRelation.isRight()) {
1176                 return Either.right(createRelation.right().value());
1177             }
1178         }
1179         return Either.left(createDataTypeResult.left().value());
1180     }
1181     
1182     private Either<GraphRelation, JanusGraphOperationStatus> addDataTypeToModel(final DataTypeDefinition dataTypeDefinition) {
1183       final String model = dataTypeDefinition.getModel();
1184       if (model == null) {
1185           return Either.left(null);
1186       }
1187       final GraphNode from = new UniqueIdData(NodeTypeEnum.Model, UniqueIdBuilder.buildModelUid(model));
1188       final GraphNode to = new UniqueIdData(NodeTypeEnum.DataType, dataTypeDefinition.getUniqueId());
1189       log.info("Connecting model {} to type {}", from, to);
1190       return janusGraphGenericDao.createRelation(from , to, GraphEdgeLabels.MODEL_ELEMENT, Collections.emptyMap());
1191   }
1192
1193     private DataTypeData buildDataTypeData(DataTypeDefinition dataTypeDefinition, String ctUniqueId) {
1194         DataTypeData dataTypeData = new DataTypeData(dataTypeDefinition);
1195         dataTypeData.getDataTypeDataDefinition().setUniqueId(ctUniqueId);
1196         Long creationDate = dataTypeData.getDataTypeDataDefinition().getCreationTime();
1197         if (creationDate == null) {
1198             creationDate = System.currentTimeMillis();
1199         }
1200         dataTypeData.getDataTypeDataDefinition().setCreationTime(creationDate);
1201         dataTypeData.getDataTypeDataDefinition().setModificationTime(creationDate);
1202         return dataTypeData;
1203     }
1204
1205     /**
1206      * add properties to capability type.
1207      * <p>
1208      * Per property, add a property node and associate it to the capability type
1209      *
1210      * @param uniqueId
1211      * @param properties
1212      * @return
1213      */
1214     private Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToDataType(final String uniqueId, final String modelName,
1215                                                                                                  final List<PropertyDefinition> properties) {
1216         Map<String, PropertyData> propertiesData = new HashMap<>();
1217         if (properties != null && !properties.isEmpty()) {
1218             for (PropertyDefinition propertyDefinition : properties) {
1219                 String propertyName = propertyDefinition.getName();
1220                 String propertyType = propertyDefinition.getType();
1221                 Either<Boolean, JanusGraphOperationStatus> validPropertyType = isValidPropertyType(propertyType, modelName);
1222                 if (validPropertyType.isRight()) {
1223                     log.debug("Data type {} contains invalid property type {}", uniqueId, propertyType);
1224                     return Either.right(validPropertyType.right().value());
1225                 }
1226                 Boolean isValid = validPropertyType.left().value();
1227                 if (isValid == null || !isValid.booleanValue()) {
1228                     log.debug("Data type {} contains invalid property type {}", uniqueId, propertyType);
1229                     return Either.right(JanusGraphOperationStatus.INVALID_TYPE);
1230                 }
1231                 Either<PropertyData, JanusGraphOperationStatus> addPropertyToNodeType = this
1232                     .addPropertyToNodeType(propertyName, propertyDefinition, NodeTypeEnum.DataType, uniqueId);
1233                 if (addPropertyToNodeType.isRight()) {
1234                     JanusGraphOperationStatus operationStatus = addPropertyToNodeType.right().value();
1235                     log.debug("Failed to associate data type {} to property {} in graph. status is {}", uniqueId, propertyName, operationStatus);
1236                     BeEcompErrorManager.getInstance()
1237                         .logInternalFlowError("AddPropertyToDataType", "Failed to associate property to data type. Status is " + operationStatus,
1238                             ErrorSeverity.ERROR);
1239                     return Either.right(operationStatus);
1240                 }
1241                 propertiesData.put(propertyName, addPropertyToNodeType.left().value());
1242             }
1243             DataTypeData dataTypeData = new DataTypeData();
1244             dataTypeData.getDataTypeDataDefinition().setUniqueId(uniqueId);
1245             long modificationTime = System.currentTimeMillis();
1246             dataTypeData.getDataTypeDataDefinition().setModificationTime(modificationTime);
1247             Either<DataTypeData, JanusGraphOperationStatus> updateNode = janusGraphGenericDao.updateNode(dataTypeData, DataTypeData.class);
1248             if (updateNode.isRight()) {
1249                 JanusGraphOperationStatus operationStatus = updateNode.right().value();
1250                 log.debug("Failed to update modification time data type {} from graph. status is {}", uniqueId, operationStatus);
1251                 BeEcompErrorManager.getInstance()
1252                     .logInternalFlowError("AddPropertyToDataType", "Failed to fetch data type. Status is " + operationStatus, ErrorSeverity.ERROR);
1253                 return Either.right(operationStatus);
1254             } else {
1255                 log.debug("Update data type uid {}. Set modification time to {}", uniqueId, modificationTime);
1256             }
1257         }
1258         return Either.left(propertiesData);
1259     }
1260     
1261     public Either<DataTypeDefinition, JanusGraphOperationStatus> getDataTypeByNameValidForModel(final String name, final String modelName) {
1262         final Either<DataTypeData, JanusGraphOperationStatus> dataTypesRes = janusGraphGenericDao
1263             .getNode(GraphPropertiesDictionary.NAME.getProperty(), name, DataTypeData.class, modelName);
1264         if (dataTypesRes.isRight()) {
1265             final JanusGraphOperationStatus status = dataTypesRes.right().value();
1266             log.debug(DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS, name, status);
1267             return Either.right(status);
1268         }
1269         final DataTypeData dataType = dataTypesRes.left().value();
1270         final DataTypeDefinition dataTypeDefinition = new DataTypeDefinition(dataType.getDataTypeDataDefinition());
1271         final JanusGraphOperationStatus propertiesStatus = fillProperties(dataTypeDefinition.getUniqueId(), dataTypeDefinition);
1272         if (propertiesStatus != JanusGraphOperationStatus.OK) {
1273             log.error(BUSINESS_PROCESS_ERROR, FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE, dataTypeDefinition.getUniqueId());
1274             return Either.right(propertiesStatus);
1275         }
1276         final Either<ImmutablePair<DataTypeData, GraphEdge>, JanusGraphOperationStatus> parentNode = janusGraphGenericDao
1277             .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), dataTypeDefinition.getUniqueId(), GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.DataType,
1278               DataTypeData.class);
1279         log.debug(AFTER_RETRIEVING_DERIVED_FROM_NODE_OF_STATUS_IS, dataTypeDefinition.getUniqueId(), parentNode);
1280         if (parentNode.isRight()) {
1281             final JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
1282             if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
1283                 log.error(BUSINESS_PROCESS_ERROR, "Failed to find the parent data type of data type {}. status is {}", dataTypeDefinition.getUniqueId(), janusGraphOperationStatus);
1284                 return Either.right(janusGraphOperationStatus);
1285             }
1286         } else {
1287             // derived from node was found
1288             final ImmutablePair<DataTypeData, GraphEdge> immutablePair = parentNode.left().value();
1289             final DataTypeData parentDataType = immutablePair.getKey();
1290             final Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeByUid = getDataTypeByUid(parentDataType.getUniqueId());
1291             if (dataTypeByUid.isRight()) {
1292                 return Either.right(dataTypeByUid.right().value());
1293             }
1294             DataTypeDefinition parentDataTypeDefinition = dataTypeByUid.left().value();
1295             dataTypeDefinition.setDerivedFrom(parentDataTypeDefinition);
1296         }
1297         return Either.left(dataTypeDefinition);
1298   }
1299
1300     /**
1301      * Build Data type object from graph by unique id
1302      *
1303      * @param uniqueId
1304      * @return
1305      */
1306     public Either<DataTypeDefinition, JanusGraphOperationStatus> getDataTypeByUid(String uniqueId) {
1307         Either<DataTypeDefinition, JanusGraphOperationStatus> result = null;
1308         Either<DataTypeData, JanusGraphOperationStatus> dataTypesRes = janusGraphGenericDao
1309             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, DataTypeData.class);
1310         if (dataTypesRes.isRight()) {
1311             JanusGraphOperationStatus status = dataTypesRes.right().value();
1312             log.debug(DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS, uniqueId, status);
1313             return Either.right(status);
1314         }
1315         DataTypeData ctData = dataTypesRes.left().value();
1316         DataTypeDefinition dataTypeDefinition = new DataTypeDefinition(ctData.getDataTypeDataDefinition());
1317         JanusGraphOperationStatus propertiesStatus = fillProperties(uniqueId, dataTypeDefinition);
1318         if (propertiesStatus != JanusGraphOperationStatus.OK) {
1319             log.error(FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE, uniqueId);
1320             return Either.right(propertiesStatus);
1321         }
1322         Either<ImmutablePair<DataTypeData, GraphEdge>, JanusGraphOperationStatus> parentNode = janusGraphGenericDao
1323             .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.DataType,
1324                 DataTypeData.class);
1325         log.debug(AFTER_RETRIEVING_DERIVED_FROM_NODE_OF_STATUS_IS, uniqueId, parentNode);
1326         if (parentNode.isRight()) {
1327             JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
1328             if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
1329                 log.error("Failed to find the parent data type of data type {}. status is {}", uniqueId, janusGraphOperationStatus);
1330                 result = Either.right(janusGraphOperationStatus);
1331                 return result;
1332             }
1333         } else {
1334             // derived from node was found
1335             ImmutablePair<DataTypeData, GraphEdge> immutablePair = parentNode.left().value();
1336             DataTypeData parentCT = immutablePair.getKey();
1337             String parentUniqueId = parentCT.getUniqueId();
1338             Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeByUid = getDataTypeByUid(parentUniqueId);
1339             if (dataTypeByUid.isRight()) {
1340                 return Either.right(dataTypeByUid.right().value());
1341             }
1342             DataTypeDefinition parentDataTypeDefinition = dataTypeByUid.left().value();
1343             dataTypeDefinition.setDerivedFrom(parentDataTypeDefinition);
1344         }
1345         result = Either.left(dataTypeDefinition);
1346         return result;
1347     }
1348
1349     private JanusGraphOperationStatus fillProperties(String uniqueId, DataTypeDefinition dataTypeDefinition) {
1350         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> findPropertiesOfNode = this
1351             .findPropertiesOfNode(NodeTypeEnum.DataType, uniqueId);
1352         if (findPropertiesOfNode.isRight()) {
1353             JanusGraphOperationStatus janusGraphOperationStatus = findPropertiesOfNode.right().value();
1354             log.debug("After looking for properties of vertex {}. status is {}", uniqueId, janusGraphOperationStatus);
1355             if (JanusGraphOperationStatus.NOT_FOUND.equals(janusGraphOperationStatus)) {
1356                 return JanusGraphOperationStatus.OK;
1357             } else {
1358                 return janusGraphOperationStatus;
1359             }
1360         } else {
1361             Map<String, PropertyDefinition> properties = findPropertiesOfNode.left().value();
1362             if (properties != null && !properties.isEmpty()) {
1363                 List<PropertyDefinition> listOfProps = new ArrayList<>();
1364                 for (Entry<String, PropertyDefinition> entry : properties.entrySet()) {
1365                     String propName = entry.getKey();
1366                     PropertyDefinition propertyDefinition = entry.getValue();
1367                     PropertyDefinition newPropertyDefinition = new PropertyDefinition(propertyDefinition);
1368                     newPropertyDefinition.setName(propName);
1369                     listOfProps.add(newPropertyDefinition);
1370                 }
1371                 dataTypeDefinition.setProperties(listOfProps);
1372             }
1373             return JanusGraphOperationStatus.OK;
1374         }
1375     }
1376
1377     private Either<DataTypeDefinition, StorageOperationStatus> addDataType(DataTypeDefinition dataTypeDefinition, boolean inTransaction) {
1378         Either<DataTypeDefinition, StorageOperationStatus> result = null;
1379         try {
1380             Either<DataTypeData, JanusGraphOperationStatus> eitherStatus = addDataTypeToGraph(dataTypeDefinition);
1381             if (eitherStatus.isRight()) {
1382                 log.debug("Failed to add data type {} to Graph. status is {}", dataTypeDefinition, eitherStatus.right().value().name());
1383                 BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError("AddDataType", "DataType");
1384                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(eitherStatus.right().value()));
1385                 return result;
1386             } else {
1387                 DataTypeData capabilityTypeData = eitherStatus.left().value();
1388                 DataTypeDefinition dataTypeDefResult = convertDTDataToDTDefinition(capabilityTypeData);
1389                 log.debug("The returned CapabilityTypeDefinition is {}", dataTypeDefResult);
1390                 result = Either.left(dataTypeDefResult);
1391                 return result;
1392             }
1393         } finally {
1394             if (!inTransaction) {
1395                 if (result == null || result.isRight()) {
1396                     log.error(GOING_TO_EXECUTE_ROLLBACK_ON_GRAPH);
1397                     janusGraphGenericDao.rollback();
1398                 } else {
1399                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_GRAPH);
1400                     janusGraphGenericDao.commit();
1401                 }
1402             }
1403         }
1404     }
1405
1406     @Override
1407     public Either<DataTypeDefinition, StorageOperationStatus> addDataType(DataTypeDefinition dataTypeDefinition) {
1408         return addDataType(dataTypeDefinition, true);
1409     }
1410
1411     @Override
1412     public Either<DataTypeDefinition, StorageOperationStatus> getDataTypeByName(final String name, final String validForModel, final boolean inTransaction) {
1413         Either<DataTypeDefinition, StorageOperationStatus> result = null;
1414         try {
1415             Either<DataTypeDefinition, JanusGraphOperationStatus> ctResult = this.getDataTypeByNameValidForModel(name, validForModel);
1416             if (ctResult.isRight()) {
1417                 JanusGraphOperationStatus status = ctResult.right().value();
1418                 if (status != JanusGraphOperationStatus.NOT_FOUND) {
1419                     log.error("Failed to retrieve information on capability type {} status is {}", name, status);
1420                 }
1421                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(ctResult.right().value()));
1422                 return result;
1423             }
1424             result = Either.left(ctResult.left().value());
1425             return result;
1426         } finally {
1427             if (!inTransaction) {
1428                 if (result == null || result.isRight()) {
1429                     log.error(GOING_TO_EXECUTE_ROLLBACK_ON_GRAPH);
1430                     janusGraphGenericDao.rollback();
1431                 } else {
1432                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_GRAPH);
1433                     janusGraphGenericDao.commit();
1434                 }
1435             }
1436         }
1437     }
1438
1439     @Override
1440     public Either<DataTypeDefinition, StorageOperationStatus> getDataTypeByName(final String name, final String validForModel) {
1441         return getDataTypeByName(name, validForModel, true);
1442     }
1443     
1444     public Either<DataTypeDefinition, StorageOperationStatus> getDataTypeByUidWithoutDerived(String uid, boolean inTransaction) {
1445         Either<DataTypeDefinition, StorageOperationStatus> result = null;
1446         try {
1447             Either<DataTypeDefinition, JanusGraphOperationStatus> ctResult = this.getDataTypeByUidWithoutDerivedDataTypes(uid);
1448             if (ctResult.isRight()) {
1449                 JanusGraphOperationStatus status = ctResult.right().value();
1450                 if (status != JanusGraphOperationStatus.NOT_FOUND) {
1451                   log.error(BUSINESS_PROCESS_ERROR, "Failed to retrieve information on data type {} status is {}", uid, status);
1452                 }
1453                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(ctResult.right().value()));
1454                 return result;
1455             }
1456             result = Either.left(ctResult.left().value());
1457             return result;
1458         } finally {
1459             if (!inTransaction) {
1460                 if (result == null || result.isRight()) {
1461                     log.error(GOING_TO_EXECUTE_ROLLBACK_ON_GRAPH);
1462                     janusGraphGenericDao.rollback();
1463                 } else {
1464                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_GRAPH);
1465                     janusGraphGenericDao.commit();
1466                 }
1467             }
1468         }
1469     }
1470
1471     public Either<DataTypeDefinition, JanusGraphOperationStatus> getDataTypeByUidWithoutDerivedDataTypes(String uniqueId) {
1472         Either<DataTypeData, JanusGraphOperationStatus> dataTypesRes = janusGraphGenericDao
1473             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, DataTypeData.class);
1474         if (dataTypesRes.isRight()) {
1475             JanusGraphOperationStatus status = dataTypesRes.right().value();
1476             log.debug(DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS, uniqueId, status);
1477             return Either.right(status);
1478         }
1479         DataTypeData ctData = dataTypesRes.left().value();
1480         DataTypeDefinition dataTypeDefinition = new DataTypeDefinition(ctData.getDataTypeDataDefinition());
1481         JanusGraphOperationStatus propertiesStatus = fillProperties(uniqueId, dataTypeDefinition);
1482         if (propertiesStatus != JanusGraphOperationStatus.OK) {
1483             log.error(FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE, uniqueId);
1484             return Either.right(propertiesStatus);
1485         }
1486         return Either.left(dataTypeDefinition);
1487     }
1488
1489     /**
1490      * convert between graph Node object to Java object
1491      *
1492      * @param dataTypeData
1493      * @return
1494      */
1495     protected DataTypeDefinition convertDTDataToDTDefinition(DataTypeData dataTypeData) {
1496         log.debug("The object returned after create data type is {}", dataTypeData);
1497         return new DataTypeDefinition(dataTypeData.getDataTypeDataDefinition());
1498     }
1499
1500     private Either<Boolean, JanusGraphOperationStatus> isValidPropertyType(String propertyType, final String modelName) {
1501         if (propertyType == null || propertyType.isEmpty()) {
1502             return Either.left(false);
1503         }
1504         ToscaPropertyType toscaPropertyType = ToscaPropertyType.isValidType(propertyType);
1505         if (toscaPropertyType == null) {
1506             return isDefinedInDataTypes(propertyType, modelName);
1507         } else {
1508             return Either.left(true);
1509         }
1510     }
1511
1512     public Either<Boolean, JanusGraphOperationStatus> isDefinedInDataTypes(final String propertyType, final String modelName) {
1513         Either<DataTypeDefinition, JanusGraphOperationStatus> dataType = getDataTypeByNameValidForModel(propertyType, modelName);
1514         if (dataType.isRight()) {
1515             JanusGraphOperationStatus status = dataType.right().value();
1516             if (status == JanusGraphOperationStatus.NOT_FOUND) {
1517                 return Either.left(false);
1518             }
1519             return Either.right(status);
1520         }
1521         return Either.left(true);
1522     }
1523
1524     public Either<Map<String, Map<String, DataTypeDefinition>>, JanusGraphOperationStatus> getAllDataTypes() {
1525         final Map<String, Map<String, DataTypeDefinition>> dataTypes = new HashMap<>();
1526         Either<Map<String, Map<String, DataTypeDefinition>>, JanusGraphOperationStatus> result = Either.left(dataTypes);
1527         final Map<String, DataTypeDefinition> allDataTypesFound = new HashMap<>();
1528         
1529         final Map<String, List<String>> dataTypeUidstoModels = dataTypeOperation.getAllDataTypeUidsToModels();
1530
1531         if (dataTypeUidstoModels != null) {
1532             log.trace("Number of data types to load is {}", dataTypeUidstoModels.size());
1533             for (Map.Entry<String, List<String>> entry : dataTypeUidstoModels.entrySet()) {
1534                 log.trace("Going to fetch data type with uid {}", entry.getKey());
1535                 Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeByUid = this
1536                     .getAndAddDataTypeByUid(entry.getKey(), allDataTypesFound);
1537                 if (dataTypeByUid.isRight()) {
1538                     JanusGraphOperationStatus status = dataTypeByUid.right().value();
1539                     if (status == JanusGraphOperationStatus.NOT_FOUND) {
1540                         status = JanusGraphOperationStatus.INVALID_ID;
1541                     }
1542                     return Either.right(status);
1543                 }
1544                 for (final String model: entry.getValue()) {
1545                     if (!dataTypes.containsKey(model)) {
1546                         dataTypes.put(model, new HashMap<String, DataTypeDefinition>());
1547                     }
1548                     DataTypeDefinition dataTypeDefinition = allDataTypesFound.get(entry.getKey());
1549                     dataTypes.get(model).put(dataTypeDefinition.getName(), dataTypeDefinition);
1550                 }
1551             }
1552             
1553         }
1554         if (log.isTraceEnabled()) {
1555             if (result.isRight()) {
1556                 log.trace("After fetching all data types {}", result);
1557             } else {
1558                 Map<String, Map<String, DataTypeDefinition>> map = result.left().value();
1559                 if (map != null) {
1560                     String types = map.keySet().stream().collect(Collectors.joining(",", "[", "]"));
1561                     log.trace("After fetching all data types {} ", types);
1562                 }
1563             }
1564         }
1565         return result;
1566     }
1567
1568     /**
1569      * Build Data type object from graph by unique id
1570      *
1571      * @param uniqueId
1572      * @return
1573      */
1574     private Either<DataTypeDefinition, JanusGraphOperationStatus> getAndAddDataTypeByUid(String uniqueId,
1575                                                                                          Map<String, DataTypeDefinition> allDataTypes) {
1576         Either<DataTypeDefinition, JanusGraphOperationStatus> result = null;
1577         if (allDataTypes.containsKey(uniqueId)) {
1578             return Either.left(allDataTypes.get(uniqueId));
1579         }
1580         Either<DataTypeData, JanusGraphOperationStatus> dataTypesRes = janusGraphGenericDao
1581             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, DataTypeData.class);
1582         if (dataTypesRes.isRight()) {
1583             JanusGraphOperationStatus status = dataTypesRes.right().value();
1584             log.debug(DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS, uniqueId, status);
1585             return Either.right(status);
1586         }
1587         DataTypeData ctData = dataTypesRes.left().value();
1588         DataTypeDefinition dataTypeDefinition = new DataTypeDefinition(ctData.getDataTypeDataDefinition());
1589         JanusGraphOperationStatus propertiesStatus = fillProperties(uniqueId, dataTypeDefinition);
1590         if (propertiesStatus != JanusGraphOperationStatus.OK) {
1591             log.error(FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE, uniqueId);
1592             return Either.right(propertiesStatus);
1593         }
1594         allDataTypes.put(dataTypeDefinition.getUniqueId(), dataTypeDefinition);
1595         String derivedFrom = dataTypeDefinition.getDerivedFromName();
1596         if (allDataTypes.containsKey(derivedFrom)) {
1597             DataTypeDefinition parentDataTypeDefinition = allDataTypes.get(derivedFrom);
1598             dataTypeDefinition.setDerivedFrom(parentDataTypeDefinition);
1599             return Either.left(dataTypeDefinition);
1600         }
1601         Either<ImmutablePair<DataTypeData, GraphEdge>, JanusGraphOperationStatus> parentNode = janusGraphGenericDao
1602             .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.DataType,
1603                 DataTypeData.class);
1604         log.debug(AFTER_RETRIEVING_DERIVED_FROM_NODE_OF_STATUS_IS, uniqueId, parentNode);
1605         if (parentNode.isRight()) {
1606             JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
1607             if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
1608                 log.error("Failed to find the parent data type of data type {}. status is {}", uniqueId, janusGraphOperationStatus);
1609                 result = Either.right(janusGraphOperationStatus);
1610                 return result;
1611             }
1612         } else {
1613             // derived from node was found
1614             ImmutablePair<DataTypeData, GraphEdge> immutablePair = parentNode.left().value();
1615             DataTypeData parentCT = immutablePair.getKey();
1616             String parentUniqueId = parentCT.getUniqueId();
1617             Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeByUid = getDataTypeByUid(parentUniqueId);
1618             if (dataTypeByUid.isRight()) {
1619                 return Either.right(dataTypeByUid.right().value());
1620             }
1621             DataTypeDefinition parentDataTypeDefinition = dataTypeByUid.left().value();
1622             dataTypeDefinition.setDerivedFrom(parentDataTypeDefinition);
1623             final var model = getModel(uniqueId);
1624             if (StringUtils.isNotEmpty(model)) {
1625                 dataTypeDefinition.setModel(model);
1626             }
1627         }
1628         result = Either.left(dataTypeDefinition);
1629         return result;
1630     }
1631
1632     private String getModel(final String uniqueId) {
1633         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> model = janusGraphGenericDao.getParentNode(
1634             UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, GraphEdgeLabels.MODEL_ELEMENT,
1635             NodeTypeEnum.Model, ModelData.class);
1636         return model.isLeft() ? model.left().value().getLeft().getName() : StringUtils.EMPTY;
1637     }
1638
1639     public Either<String, JanusGraphOperationStatus> checkInnerType(PropertyDataDefinition propDataDef) {
1640         String propertyType = propDataDef.getType();
1641         ToscaPropertyType type = ToscaPropertyType.isValidType(propertyType);
1642         return getInnerType(type, propDataDef::getSchema);
1643     }
1644
1645     public Either<Object, Boolean> validateAndUpdatePropertyValue(String propertyType, String value, boolean isValidate, String innerType,
1646                                                                   Map<String, DataTypeDefinition> dataTypes) {
1647         log.trace("Going to validate property value and its type. type = {}, value = {}", propertyType, value);
1648         ToscaPropertyType type = getType(propertyType);
1649         if (isValidate) {
1650             if (type == null) {
1651                 DataTypeDefinition dataTypeDefinition = dataTypes.get(propertyType);
1652                 ImmutablePair<JsonElement, Boolean> validateResult = dataTypeValidatorConverter
1653                     .validateAndUpdate(value, dataTypeDefinition, dataTypes);
1654                 if (Boolean.FALSE.equals(validateResult.right)) {
1655                     log.debug(THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID, value, propertyType);
1656                     return Either.right(false);
1657                 }
1658                 JsonElement jsonElement = validateResult.left;
1659                 String valueFromJsonElement = getValueFromJsonElement(jsonElement);
1660                 return Either.left(valueFromJsonElement);
1661             }
1662             log.trace("before validating property type {}", propertyType);
1663             boolean isValidProperty = isValidValue(type, value, innerType, dataTypes);
1664             if (!isValidProperty) {
1665                 log.debug(THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID, value, type);
1666                 return Either.right(false);
1667             }
1668         }
1669         Object convertedValue = value;
1670         if (!isEmptyValue(value) && isValidate) {
1671             PropertyValueConverter converter = type.getConverter();
1672             convertedValue = converter.convert(value, innerType, dataTypes);
1673         }
1674         return Either.left(convertedValue);
1675     }
1676
1677     public Either<Object, Boolean> validateAndUpdatePropertyValue(String propertyType, String value, String innerType,
1678                                                                   Map<String, DataTypeDefinition> dataTypes) {
1679         return validateAndUpdatePropertyValue(propertyType, value, true, innerType, dataTypes);
1680     }
1681
1682     public <T extends GraphNode> Either<List<PropertyDefinition>, StorageOperationStatus> getAllPropertiesRec(String uniqueId, NodeTypeEnum nodeType,
1683                                                                                                               Class<T> clazz) {
1684         return this.findPropertiesOfNode(nodeType, uniqueId).right().bind(this::handleNotFoundProperties).left()
1685             .bind(props -> getAllDerivedFromChainProperties(uniqueId, nodeType, clazz, props.values()));
1686     }
1687
1688     private Either<Map<String, PropertyDefinition>, StorageOperationStatus> handleNotFoundProperties(
1689         JanusGraphOperationStatus janusGraphOperationStatus) {
1690         if (janusGraphOperationStatus == JanusGraphOperationStatus.NOT_FOUND) {
1691             return Either.left(new HashMap<>());
1692         }
1693         return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(janusGraphOperationStatus));
1694     }
1695
1696     private <T extends GraphNode> Either<List<PropertyDefinition>, StorageOperationStatus> getAllDerivedFromChainProperties(String uniqueId,
1697                                                                                                                             NodeTypeEnum nodeType,
1698                                                                                                                             Class<T> clazz,
1699                                                                                                                             Collection<PropertyDefinition> nodeProps) {
1700         List<PropertyDefinition> accumulatedProps = new ArrayList<>(nodeProps);
1701         String currentNodeUid = uniqueId;
1702         Either<T, StorageOperationStatus> derivedFrom;
1703         while ((derivedFrom = derivedFromOperation.getDerivedFromChild(currentNodeUid, nodeType, clazz)).isLeft()) {
1704             currentNodeUid = derivedFrom.left().value().getUniqueId();
1705             JanusGraphOperationStatus janusGraphOperationStatus = fillPropertiesList(currentNodeUid, nodeType, accumulatedProps::addAll);
1706             if (janusGraphOperationStatus != JanusGraphOperationStatus.OK) {
1707                 log.debug("failed to fetch properties for type {} with id {}", nodeType, currentNodeUid);
1708                 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(janusGraphOperationStatus));
1709             }
1710         }
1711         StorageOperationStatus getDerivedResult = derivedFrom.right().value();
1712         return isReachedEndOfDerivedFromChain(getDerivedResult) ? Either.left(accumulatedProps) : Either.right(getDerivedResult);
1713     }
1714
1715     private boolean isReachedEndOfDerivedFromChain(StorageOperationStatus getDerivedResult) {
1716         return getDerivedResult == StorageOperationStatus.NOT_FOUND;
1717     }
1718
1719     /*
1720      * @Override public PropertyOperation getPropertyOperation() { return this; }
1721      */
1722     public JanusGraphOperationStatus fillPropertiesList(String uniqueId, NodeTypeEnum nodeType, Consumer<List<PropertyDefinition>> propertySetter) {
1723         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> findPropertiesRes = findPropertiesifExist(uniqueId, nodeType);
1724         if (findPropertiesRes.isRight()) {
1725             return findPropertiesRes.right().value();
1726         }
1727         Map<String, PropertyDefinition> properties = findPropertiesRes.left().value();
1728         if (properties != null) {
1729             List<PropertyDefinition> propertiesAsList = properties.entrySet().stream().map(Entry::getValue).collect(Collectors.toList());
1730             propertySetter.accept(propertiesAsList);
1731         }
1732         return JanusGraphOperationStatus.OK;
1733     }
1734
1735     Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> findPropertiesifExist(String uniqueId, NodeTypeEnum nodeType) {
1736         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> findPropertiesOfNode = this.findPropertiesOfNode(nodeType, uniqueId);
1737         if (findPropertiesOfNode.isRight()) {
1738             log.debug("After looking for properties of vertex {}. status is {}", uniqueId, findPropertiesOfNode.right().value());
1739             if (findPropertiesOfNode.right().value() == JanusGraphOperationStatus.NOT_FOUND) {
1740                 return Either.left(Maps.newHashMap());
1741             }
1742             return findPropertiesOfNode;
1743         }
1744         return findPropertiesOfNode;
1745     }
1746
1747     /**
1748      * add properties to element type.
1749      * <p>
1750      * Per property, add a property node and associate it to the element type
1751      *
1752      * @param uniqueId
1753      * @param propertiesMap
1754      * @return
1755      */
1756     protected Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToElementType(String uniqueId, NodeTypeEnum nodeType,
1757                                                                                                       Map<String, PropertyDefinition> propertiesMap) {
1758         Map<String, PropertyData> propertiesData = new HashMap<>();
1759         if (propertiesMap != null) {
1760             for (Entry<String, PropertyDefinition> propertyDefinitionEntry : propertiesMap.entrySet()) {
1761                 String propertyName = propertyDefinitionEntry.getKey();
1762                 Either<PropertyData, JanusGraphOperationStatus> addPropertyToNodeType = this
1763                     .addPropertyToNodeType(propertyName, propertyDefinitionEntry.getValue(), nodeType, uniqueId);
1764                 if (addPropertyToNodeType.isRight()) {
1765                     JanusGraphOperationStatus operationStatus = addPropertyToNodeType.right().value();
1766                     log.error("Failed to associate {} {} to property {} in graph. status is {}", nodeType.getName(), uniqueId, propertyName,
1767                         operationStatus);
1768                     return Either.right(operationStatus);
1769                 }
1770                 propertiesData.put(propertyName, addPropertyToNodeType.left().value());
1771             }
1772         }
1773         return Either.left(propertiesData);
1774     }
1775
1776     public Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToElementType(String uniqueId, NodeTypeEnum elementType,
1777                                                                                                    List<PropertyDefinition> properties) {
1778         Map<String, PropertyDefinition> propMap;
1779         if (properties == null) {
1780             propMap = null;
1781         } else {
1782             propMap = properties.stream().collect(Collectors.toMap(PropertyDataDefinition::getName, propDef -> propDef));
1783         }
1784         return addPropertiesToElementType(uniqueId, elementType, propMap);
1785     }
1786
1787     @Override
1788     public Either<DataTypeDefinition, StorageOperationStatus> updateDataType(DataTypeDefinition newDataTypeDefinition,
1789                                                                              DataTypeDefinition oldDataTypeDefinition) {
1790         return updateDataType(newDataTypeDefinition, oldDataTypeDefinition, true);
1791     }
1792
1793     private Either<DataTypeDefinition, StorageOperationStatus> updateDataType(DataTypeDefinition newDataTypeDefinition,
1794                                                                               DataTypeDefinition oldDataTypeDefinition, boolean inTransaction) {
1795         Either<DataTypeDefinition, StorageOperationStatus> result = null;
1796         try {
1797             List<PropertyDefinition> newProperties = newDataTypeDefinition.getProperties();
1798             List<PropertyDefinition> oldProperties = oldDataTypeDefinition.getProperties();
1799             String newDerivedFromName = newDataTypeDefinition.getDerivedFromName();
1800             String oldDerivedFromName = oldDataTypeDefinition.getDerivedFromName();
1801             String dataTypeName = newDataTypeDefinition.getName();
1802             List<PropertyDefinition> propertiesToAdd = new ArrayList<>();
1803             if (isPropertyOmitted(newProperties, oldProperties, dataTypeName) || isPropertyTypeChanged(dataTypeName, newProperties, oldProperties,
1804                 propertiesToAdd) || isDerivedFromNameChanged(dataTypeName, newDerivedFromName, oldDerivedFromName)) {
1805                 log.debug("The new data type {} is invalid.", dataTypeName);
1806                 result = Either.right(StorageOperationStatus.CANNOT_UPDATE_EXISTING_ENTITY);
1807                 return result;
1808             }
1809             if (propertiesToAdd == null || propertiesToAdd.isEmpty()) {
1810                 log.debug("No new properties has been defined in the new data type {}", newDataTypeDefinition);
1811                 result = Either.right(StorageOperationStatus.OK);
1812                 return result;
1813             }
1814             Map<String, String> newDescriptions = getPropertyDescriptionsToUpdate(oldProperties, newProperties);
1815             if (MapUtils.isNotEmpty(newDescriptions)) {
1816                 JanusGraphOperationStatus updatePropertiesStatus = updateDataTypePropertyDescriptions(oldDataTypeDefinition.getUniqueId(),
1817                     newDescriptions);
1818                 if (updatePropertiesStatus != JanusGraphOperationStatus.OK) {
1819                     log.debug("#updateDataType - Failed to update the descriptions of the properties of the data type {}. Status is {}",
1820                         oldDataTypeDefinition, updatePropertiesStatus);
1821                     BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError(UPDATE_DATA_TYPE, PROPERTY);
1822                     result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(updatePropertiesStatus));
1823                     return result;
1824                 }
1825             }
1826             Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToDataType = addPropertiesToDataType(
1827                 oldDataTypeDefinition.getUniqueId(), oldDataTypeDefinition.getModel(), propertiesToAdd);
1828             if (addPropertiesToDataType.isRight()) {
1829                 log.debug("Failed to update data type {} to Graph. Status is {}", oldDataTypeDefinition,
1830                     addPropertiesToDataType.right().value().name());
1831                 BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError(UPDATE_DATA_TYPE, PROPERTY);
1832                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertiesToDataType.right().value()));
1833                 return result;
1834             } else {
1835                 Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeByUid = this.getDataTypeByUid(oldDataTypeDefinition.getUniqueId());
1836                 if (dataTypeByUid.isRight()) {
1837                     JanusGraphOperationStatus status = addPropertiesToDataType.right().value();
1838                     log.debug("Failed to get data type {} after update. Status is {}", oldDataTypeDefinition.getUniqueId(), status.name());
1839                     BeEcompErrorManager.getInstance().logBeFailedRetrieveNodeError(UPDATE_DATA_TYPE, PROPERTY, status.name());
1840                     result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1841                 } else {
1842                     result = Either.left(dataTypeByUid.left().value());
1843                 }
1844             }
1845             return result;
1846         } finally {
1847             if (!inTransaction) {
1848                 if (result == null || result.isRight()) {
1849                     log.error(GOING_TO_EXECUTE_ROLLBACK_ON_GRAPH);
1850                     janusGraphGenericDao.rollback();
1851                 } else {
1852                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_GRAPH);
1853                     janusGraphGenericDao.commit();
1854                 }
1855             }
1856         }
1857     }
1858
1859     private boolean isPropertyTypeChanged(String dataTypeName, List<PropertyDefinition> newProperties, List<PropertyDefinition> oldProperties,
1860                                           List<PropertyDefinition> outputPropertiesToAdd) {
1861         if (newProperties != null && oldProperties != null) {
1862             Map<String, PropertyDefinition> newPropsMapper = newProperties.stream()
1863                 .collect(Collectors.toMap(PropertyDataDefinition::getName, p -> p));
1864             Map<String, PropertyDefinition> oldPropsMapper = oldProperties.stream()
1865                 .collect(Collectors.toMap(PropertyDataDefinition::getName, p -> p));
1866             for (Entry<String, PropertyDefinition> newPropertyEntry : newPropsMapper.entrySet()) {
1867                 String propName = newPropertyEntry.getKey();
1868                 PropertyDefinition propDef = newPropertyEntry.getValue();
1869                 PropertyDefinition oldPropertyDefinition = oldPropsMapper.get(propName);
1870                 if (oldPropertyDefinition == null) {
1871                     log.debug("New property {} received in the data type {}", propName, dataTypeName);
1872                     outputPropertiesToAdd.add(propDef);
1873                     continue;
1874                 }
1875                 String oldType = oldPropertyDefinition.getType();
1876                 String oldEntryType = getEntryType(oldPropertyDefinition);
1877                 String newType = propDef.getType();
1878                 String newEntryType = getEntryType(propDef);
1879                 if (!oldType.equals(newType)) {
1880                     log.debug("Existing property {} in data type {} has a differnet type {} than the new one {}", propName, dataTypeName, oldType,
1881                         newType);
1882                     return true;
1883                 }
1884                 if (!equalsEntryTypes(oldEntryType, newEntryType)) {
1885                     log.debug("Existing property {} in data type {} has a differnet entry type {} than the new one {}", propName, dataTypeName,
1886                         oldEntryType, newEntryType);
1887                     return true;
1888                 }
1889             }
1890         }
1891         return false;
1892     }
1893
1894     private boolean equalsEntryTypes(String oldEntryType, String newEntryType) {
1895         if (oldEntryType == null && newEntryType == null) {
1896             return true;
1897         } else if (oldEntryType != null && newEntryType != null) {
1898             return oldEntryType.equals(newEntryType);
1899         } else {
1900             return false;
1901         }
1902     }
1903
1904     private String getEntryType(PropertyDefinition oldPropertyDefinition) {
1905         String entryType = null;
1906         SchemaDefinition schema = oldPropertyDefinition.getSchema();
1907         if (schema != null) {
1908             PropertyDataDefinition schemaProperty = schema.getProperty();
1909             if (schemaProperty != null) {
1910                 entryType = schemaProperty.getType();
1911             }
1912         }
1913         return entryType;
1914     }
1915
1916     private boolean isPropertyOmitted(List<PropertyDefinition> newProperties, List<PropertyDefinition> oldProperties, String dataTypeName) {
1917         boolean isValid = validateChangeInCaseOfEmptyProperties(newProperties, oldProperties, dataTypeName);
1918         if (!isValid) {
1919             log.debug("At least one property is missing in the new data type {}", dataTypeName);
1920             return false;
1921         }
1922         if (newProperties != null && oldProperties != null) {
1923             List<String> newProps = newProperties.stream().map(PropertyDataDefinition::getName).collect(Collectors.toList());
1924             List<String> oldProps = oldProperties.stream().map(PropertyDataDefinition::getName).collect(Collectors.toList());
1925             if (!newProps.containsAll(oldProps)) {
1926                 StringJoiner joiner = new StringJoiner(",", "[", "]");
1927                 newProps.forEach(joiner::add);
1928                 log.debug("Properties {} in data type {} are missing, but they already defined in the existing data type", joiner.toString(),
1929                     dataTypeName);
1930                 return true;
1931             }
1932         }
1933         return false;
1934     }
1935
1936     private boolean validateChangeInCaseOfEmptyProperties(List<PropertyDefinition> newProperties, List<PropertyDefinition> oldProperties,
1937                                                           String dataTypeName) {
1938         if (newProperties != null) {
1939             if (newProperties.isEmpty()) {
1940                 newProperties = null;
1941             }
1942         }
1943         if (oldProperties != null) {
1944             if (oldProperties.isEmpty()) {
1945                 oldProperties = null;
1946             }
1947         }
1948         if ((newProperties == null && oldProperties == null) || (newProperties != null && oldProperties != null)) {
1949             return true;
1950         }
1951         return false;
1952     }
1953
1954     private boolean isDerivedFromNameChanged(String dataTypeName, String newDerivedFromName, String oldDerivedFromName) {
1955         if (newDerivedFromName != null) {
1956             boolean isEqual = newDerivedFromName.equals(oldDerivedFromName);
1957             if (!isEqual) {
1958                 log.debug("The new datatype {} derived from another data type {} than the existing one {}", dataTypeName, newDerivedFromName,
1959                     oldDerivedFromName);
1960             }
1961             return !isEqual;
1962         } else if (oldDerivedFromName == null) {
1963             return false;
1964         } else {// new=null, old != null
1965             log.debug("The new datatype {} derived from another data type {} than the existing one {}", dataTypeName, newDerivedFromName,
1966                 oldDerivedFromName);
1967             return true;
1968         }
1969     }
1970
1971     /**
1972      * @param instanceId
1973      * @param nodeType
1974      * @return
1975      */
1976     public Either<Integer, StorageOperationStatus> increaseAndGetObjInstancePropertyCounter(String instanceId, NodeTypeEnum nodeType) {
1977         Either<JanusGraph, JanusGraphOperationStatus> graphResult = janusGraphGenericDao.getGraph();
1978         if (graphResult.isRight()) {
1979             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(graphResult.right().value()));
1980         }
1981         Either<JanusGraphVertex, JanusGraphOperationStatus> vertexService = janusGraphGenericDao
1982             .getVertexByProperty(UniqueIdBuilder.getKeyByNodeType(nodeType), instanceId);
1983         if (vertexService.isRight()) {
1984             log.debug("failed to fetch vertex of resource instance for id = {}", instanceId);
1985             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(vertexService.right().value()));
1986         }
1987         Vertex vertex = vertexService.left().value();
1988         VertexProperty<Object> vertexProperty = vertex.property(GraphPropertiesDictionary.PROPERTY_COUNTER.getProperty());
1989         Integer counter = 0;
1990         if (vertexProperty.isPresent() && vertexProperty.value() != null) {
1991             counter = (Integer) vertexProperty.value();
1992         }
1993         counter++;
1994         vertex.property(GraphPropertiesDictionary.PROPERTY_COUNTER.getProperty(), counter);
1995         return Either.left(counter);
1996     }
1997
1998     public Either<List<PropertyDefinition>, JanusGraphOperationStatus> validatePropertiesUniqueness(
1999         Map<String, PropertyDefinition> inheritedProperties, List<PropertyDefinition> properties) {
2000         Either<List<PropertyDefinition>, JanusGraphOperationStatus> result = Either.left(properties);
2001         for (PropertyDefinition property : properties) {
2002             JanusGraphOperationStatus status = validatePropertyUniqueness(inheritedProperties, property);
2003             if (status != JanusGraphOperationStatus.OK) {
2004                 result = Either.right(status);
2005                 break;
2006             }
2007         }
2008         return result;
2009     }
2010
2011     /**
2012      * Validates uniqueness of examined property by comparing it with properties in propertiesOfType and updates if need type and inner type of the
2013      * property.
2014      */
2015     private JanusGraphOperationStatus validatePropertyUniqueness(Map<String, PropertyDefinition> inheritedProperties, PropertyDefinition property) {
2016         String propertyName = property.getName();
2017         String propertyType = property.getType();
2018         JanusGraphOperationStatus result = JanusGraphOperationStatus.OK;
2019         if (inheritedProperties.containsKey(propertyName)) {
2020             PropertyDefinition defaultProperty = inheritedProperties.get(propertyName);
2021             if (typesMismatch(propertyType, defaultProperty.getType())) {
2022                 log.error("#validatePropertyUniqueness - Property with name {} and different type already exists.", propertyName);
2023                 result = JanusGraphOperationStatus.PROPERTY_NAME_ALREADY_EXISTS;
2024             } else {
2025                 property.setType(defaultProperty.getType());
2026                 String innerType = defaultProperty.getSchemaType();
2027                 PropertyDataDefinition schemaProperty = property.getSchemaProperty();
2028                 if (schemaProperty != null) {
2029                     schemaProperty.setType(innerType);
2030                 }
2031             }
2032         }
2033         return result;
2034     }
2035
2036     private boolean typesMismatch(String type1, String type2) {
2037         return type1 != null && type2 != null && !type2.equals(type1);
2038     }
2039
2040     public <T extends GraphNode> Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> getAllTypePropertiesFromAllDerivedFrom(
2041         String nextParentUid, NodeTypeEnum nodeType, Class<T> clazz) {
2042         Map<String, PropertyDefinition> allProperies = new HashMap<>();
2043         return getTypePropertiesFromDerivedFromRecursively(nextParentUid, allProperies, nodeType, clazz);
2044     }
2045
2046     private <T extends GraphNode> Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> getTypePropertiesFromDerivedFromRecursively(
2047         String nextParentUid, Map<String, PropertyDefinition> allProperies, NodeTypeEnum nodeType, Class<T> clazz) {
2048         JanusGraphOperationStatus error;
2049         Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
2050             .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(nodeType), nextParentUid, GraphEdgeLabels.DERIVED_FROM, nodeType, clazz);
2051         if (childrenNodes.isRight()) {
2052             if (childrenNodes.right().value() != JanusGraphOperationStatus.NOT_FOUND) {
2053                 error = childrenNodes.right().value();
2054                 log.debug("#getTypePropertiesFromDerivedFromRecursively - Couldn't fetch derived from node with UID {}, error: {}", nextParentUid,
2055                     error);
2056                 return Either.right(error);
2057             } else {
2058                 log.debug("#getTypePropertiesFromDerivedFromRecursively - Derived from node is not found with UID {} - this is OK for root.",
2059                     nextParentUid);
2060                 return Either.left(allProperies);
2061             }
2062         } else {
2063             Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> allPropertiesOfTypeRes = findPropertiesOfNode(nodeType, nextParentUid);
2064             if (allPropertiesOfTypeRes.isRight() && !allPropertiesOfTypeRes.right().value().equals(JanusGraphOperationStatus.NOT_FOUND)) {
2065                 error = allPropertiesOfTypeRes.right().value();
2066                 log.error(
2067                     "#getTypePropertiesFromDerivedFromRecursively - Failed to retrieve properties for node with UID {} from graph. status is {}",
2068                     nextParentUid, error);
2069                 return Either.right(error);
2070             } else if (allPropertiesOfTypeRes.isLeft()) {
2071                 if (allProperies.isEmpty()) {
2072                     allProperies.putAll(allPropertiesOfTypeRes.left().value());
2073                 } else {
2074                     allProperies.putAll(allPropertiesOfTypeRes.left().value().entrySet().stream().filter(e -> !allProperies.containsKey(e.getKey()))
2075                         .collect(Collectors.toMap(Entry::getKey, Entry::getValue)));
2076                 }
2077             }
2078             return getTypePropertiesFromDerivedFromRecursively(childrenNodes.left().value().get(0).getLeft().getUniqueId(), allProperies, nodeType,
2079                 clazz);
2080         }
2081     }
2082
2083     private JanusGraphOperationStatus updateDataTypePropertyDescriptions(String uniqueId, Map<String, String> newDescriptions) {
2084         if (MapUtils.isNotEmpty(newDescriptions)) {
2085             Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> getDataTypePropertiesRes = janusGraphGenericDao
2086                 .getChildrenVertecies(GraphPropertiesDictionary.UNIQUE_ID.getProperty(), uniqueId, GraphEdgeLabels.PROPERTY);
2087             if (getDataTypePropertiesRes.isRight()) {
2088                 log.debug("#updateDataTypePropertiesDescriptions - Failed to fetch the property verticies of the Data type {} ", uniqueId);
2089                 return getDataTypePropertiesRes.right().value();
2090             }
2091             getDataTypePropertiesRes.left().value().stream().filter(pair -> newDescriptions.containsKey(getPropertyNameFromEdge(pair)))
2092                 .forEach(pair -> setNewDescriptionToVertex(newDescriptions.get(getPropertyNameFromEdge(pair)), pair));
2093         }
2094         return JanusGraphOperationStatus.OK;
2095     }
2096
2097     private JanusGraphVertexProperty<String> setNewDescriptionToVertex(String newDescription, ImmutablePair<JanusGraphVertex, Edge> pair) {
2098         return pair.getLeft().property(GraphPropertiesDictionary.DESCRIPTION.getProperty(), newDescription);
2099     }
2100
2101     private String getPropertyNameFromEdge(ImmutablePair<JanusGraphVertex, Edge> pair) {
2102         return (String) pair.getRight().property(GraphPropertiesDictionary.NAME.getProperty()).value();
2103     }
2104
2105     private Map<String, String> getPropertyDescriptionsToUpdate(List<PropertyDefinition> oldProperties, List<PropertyDefinition> newProperties) {
2106         Map<String, PropertyDefinition> newPropertiesMap = newProperties.stream().collect(Collectors.toMap(PropertyDefinition::getName, p -> p));
2107         return oldProperties.stream()
2108             .filter(p -> newPropertiesMap.containsKey(p.getName()) && !descriptionsEqual(p, newPropertiesMap.get(p.getName())))
2109             .collect(Collectors.toMap(PropertyDefinition::getName, p -> newPropertiesMap.get(p.getName()).getDescription()));
2110     }
2111
2112     private boolean descriptionsEqual(PropertyDefinition property, PropertyDefinition otherProperty) {
2113         if (StringUtils.isEmpty(property.getDescription()) && StringUtils.isEmpty(otherProperty.getDescription())) {
2114             return true;
2115         }
2116         if (StringUtils.isNotEmpty(property.getDescription()) && StringUtils.isEmpty(otherProperty.getDescription())) {
2117             return false;
2118         }
2119         if (StringUtils.isEmpty(property.getDescription()) && StringUtils.isNotEmpty(otherProperty.getDescription())) {
2120             return false;
2121         }
2122         return property.getDescription().equals(otherProperty.getDescription());
2123     }
2124
2125     public static class PropertyConstraintSerialiser implements JsonSerializer<PropertyConstraint> {
2126
2127         @Override
2128         public JsonElement serialize(PropertyConstraint src, Type typeOfSrc, JsonSerializationContext context) {
2129             JsonParser parser = new JsonParser();
2130             JsonObject result = new JsonObject();
2131             JsonArray jsonArray = new JsonArray();
2132             if (src instanceof InRangeConstraint) {
2133                 InRangeConstraint rangeConstraint = (InRangeConstraint) src;
2134                 jsonArray.add(parser.parse(rangeConstraint.getRangeMinValue()));
2135                 jsonArray.add(parser.parse(rangeConstraint.getRangeMaxValue()));
2136                 result.add("inRange", jsonArray);
2137             } else if (src instanceof GreaterThanConstraint) {
2138                 GreaterThanConstraint greaterThanConstraint = (GreaterThanConstraint) src;
2139                 jsonArray.add(parser.parse(greaterThanConstraint.getGreaterThan()));
2140                 result.add("greaterThan", jsonArray);
2141             } else if (src instanceof LessOrEqualConstraint) {
2142                 LessOrEqualConstraint lessOrEqualConstraint = (LessOrEqualConstraint) src;
2143                 jsonArray.add(parser.parse(lessOrEqualConstraint.getLessOrEqual()));
2144                 result.add("lessOrEqual", jsonArray);
2145             } else {
2146                 log.warn("PropertyConstraint {} is not supported. Ignored.", src.getClass().getName());
2147             }
2148             return result;
2149         }
2150     }
2151
2152     public static class PropertyConstraintDeserialiser implements JsonDeserializer<PropertyConstraint> {
2153
2154         private static final String THE_VALUE_OF_GREATER_THAN_CONSTRAINT_IS_NULL = "The value of GreaterThanConstraint is null";
2155
2156         @Override
2157         public PropertyConstraint deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
2158             PropertyConstraint propertyConstraint = null;
2159             Set<Entry<String, JsonElement>> set = json.getAsJsonObject().entrySet();
2160             if (set.size() == 1) {
2161                 Entry<String, JsonElement> element = set.iterator().next();
2162                 String key = element.getKey();
2163                 JsonElement value = element.getValue();
2164                 ConstraintType constraintType = ConstraintType.getByType(key);
2165                 if (constraintType == null) {
2166                     log.warn("ConstraintType was not found for constraint name:{}", key);
2167                 } else {
2168                     switch (constraintType) {
2169                         case IN_RANGE:
2170                             if (value != null) {
2171                                 if (value instanceof JsonArray) {
2172                                     JsonArray rangeArray = (JsonArray) value;
2173                                     if (rangeArray.size() != 2) {
2174                                         log.error("The range constraint content is invalid. value = {}", value);
2175                                     } else {
2176                                         InRangeConstraint rangeConstraint = new InRangeConstraint();
2177                                         String minValue = rangeArray.get(0).getAsString();
2178                                         String maxValue;
2179                                         JsonElement maxElement = rangeArray.get(1);
2180                                         if (maxElement.isJsonNull()) {
2181                                             maxValue = String.valueOf(maxElement.getAsJsonNull());
2182                                         } else {
2183                                             maxValue = maxElement.getAsString();
2184                                         }
2185                                         rangeConstraint.setRangeMinValue(minValue);
2186                                         rangeConstraint.setRangeMaxValue(maxValue);
2187                                         propertyConstraint = rangeConstraint;
2188                                     }
2189                                 }
2190                             } else {
2191                                 log.warn(THE_VALUE_OF_GREATER_THAN_CONSTRAINT_IS_NULL);
2192                             }
2193                             break;
2194                         case GREATER_THAN:
2195                             if (value != null) {
2196                                 String asString = value.getAsString();
2197                                 log.debug("Before adding value to GreaterThanConstraint object. value = {}", asString);
2198                                 propertyConstraint = new GreaterThanConstraint(asString);
2199                                 break;
2200                             } else {
2201                                 log.warn(THE_VALUE_OF_GREATER_THAN_CONSTRAINT_IS_NULL);
2202                             }
2203                             break;
2204                         case LESS_THAN:
2205                             if (value != null) {
2206                                 String asString = value.getAsString();
2207                                 log.debug("Before adding value to LessThanConstraint object. value = {}", asString);
2208                                 propertyConstraint = new LessThanConstraint(asString);
2209                                 break;
2210                             } else {
2211                                 log.warn("The value of LessThanConstraint is null");
2212                             }
2213                             break;
2214                         case GREATER_OR_EQUAL:
2215                             if (value != null) {
2216                                 String asString = value.getAsString();
2217                                 log.debug("Before adding value to GreaterThanConstraint object. value = {}", asString);
2218                                 propertyConstraint = new GreaterOrEqualConstraint(asString);
2219                                 break;
2220                             } else {
2221                                 log.warn("The value of GreaterOrEqualConstraint is null");
2222                             }
2223                             break;
2224                         case LESS_OR_EQUAL:
2225                             if (value != null) {
2226                                 String asString = value.getAsString();
2227                                 log.debug("Before adding value to LessOrEqualConstraint object. value = {}", asString);
2228                                 propertyConstraint = new LessOrEqualConstraint(asString);
2229                             } else {
2230                                 log.warn(THE_VALUE_OF_GREATER_THAN_CONSTRAINT_IS_NULL);
2231                             }
2232                             break;
2233                         case VALID_VALUES:
2234                             if (value != null) {
2235                                 JsonArray rangeArray = (JsonArray) value;
2236                                 if (rangeArray.size() == 0) {
2237                                     log.error("The valid values constraint content is invalid. value = {}", value);
2238                                 } else {
2239                                     ValidValuesConstraint vvConstraint = new ValidValuesConstraint();
2240                                     List<String> validValues = new ArrayList<>();
2241                                     for (JsonElement jsonElement : rangeArray) {
2242                                         String item = jsonElement.getAsString();
2243                                         validValues.add(item);
2244                                     }
2245                                     vvConstraint.setValidValues(validValues);
2246                                     propertyConstraint = vvConstraint;
2247                                 }
2248                             }
2249                             break;
2250                         case MIN_LENGTH:
2251                             if (value != null) {
2252                                 int asInt = value.getAsInt();
2253                                 log.debug("Before adding value to Min Length object. value = {}", asInt);
2254                                 propertyConstraint = new MinLengthConstraint(asInt);
2255                                 break;
2256                             } else {
2257                                 log.warn("The value of MinLengthConstraint is null");
2258                             }
2259                             break;
2260                         default:
2261                             log.warn("Key {} is not supported. Ignored.", key);
2262                     }
2263                 }
2264             }
2265             return propertyConstraint;
2266         }
2267     }
2268
2269     public static class PropertyConstraintJacksonDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer<PropertyConstraint> {
2270
2271         @Override
2272         public PropertyConstraint deserialize(com.fasterxml.jackson.core.JsonParser json, DeserializationContext context) throws IOException {
2273             ObjectCodec oc = json.getCodec();
2274             JsonNode node = oc.readTree(json);
2275             return null;
2276         }
2277     }
2278
2279 }