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