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