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