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