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