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