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