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