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