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