Service Consumption BE
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / PropertyBusinessLogic.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.components.impl;
22
23 import com.google.gson.JsonElement;
24 import fj.data.Either;
25 import org.apache.commons.collections.CollectionUtils;
26 import org.apache.commons.collections.MapUtils;
27 import org.apache.commons.lang3.tuple.ImmutablePair;
28 import org.openecomp.sdc.be.config.BeEcompErrorManager;
29 import org.openecomp.sdc.be.dao.api.ActionStatus;
30 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
31 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
32 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
33 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
34 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
35 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
36 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
37 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
38 import org.openecomp.sdc.be.model.Component;
39 import org.openecomp.sdc.be.model.ComponentInstanceInterface;
40 import org.openecomp.sdc.be.model.ComponentParametersView;
41 import org.openecomp.sdc.be.model.DataTypeDefinition;
42 import org.openecomp.sdc.be.model.IComplexDefaultValue;
43 import org.openecomp.sdc.be.model.InterfaceDefinition;
44 import org.openecomp.sdc.be.model.PropertyDefinition;
45 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
46 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
47 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
48 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
49 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
50 import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator;
51 import org.openecomp.sdc.be.resources.data.EntryData;
52 import org.openecomp.sdc.common.api.Constants;
53 import org.openecomp.sdc.common.log.wrappers.Logger;
54 import org.openecomp.sdc.exception.ResponseFormat;
55 import org.springframework.web.context.WebApplicationContext;
56
57 import javax.servlet.ServletContext;
58 import java.util.*;
59 import java.util.function.Supplier;
60
61 @org.springframework.stereotype.Component("propertyBusinessLogic")
62 public class PropertyBusinessLogic extends BaseBusinessLogic {
63
64     private static final String CREATE_PROPERTY = "CreateProperty";
65
66     private static final Logger log = Logger.getLogger(PropertyBusinessLogic.class);
67
68     private static final String EMPTY_VALUE = null;
69
70     protected static IElementOperation getElementDao(Class<IElementOperation> class1, ServletContext context) {
71         WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
72
73         WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
74
75         return webApplicationContext.getBean(class1);
76     }
77
78     public Either<Map<String, DataTypeDefinition>, ResponseFormat> getAllDataTypes() {
79         return getAllDataTypes(applicationDataTypeCache);
80     }
81
82     /**
83      * Create new property on component in graph
84      *
85      * @param componentId
86      * @param propertyName
87      * @param newPropertyDefinition
88      * @param userId
89      * @return either properties or response format
90      */
91
92     public Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyToComponent(String componentId,
93                                                                                                 String propertyName,
94                                                                                                 PropertyDefinition newPropertyDefinition,
95                                                                                                 String userId) {
96         Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null;
97
98         validateUserExists(userId, "create Property", false);
99
100         Either<Component, StorageOperationStatus> serviceElement =
101                 toscaOperationFacade.getToscaElement(componentId);
102         if (serviceElement.isRight()) {
103             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
104             return result;
105         }
106         Component component = serviceElement.left().value();
107         NodeTypeEnum nodeType = component.getComponentType().getNodeType();
108         StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType );
109         if (!lockResult.equals(StorageOperationStatus.OK)) {
110             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(), componentId);
111             log.info("Failed to lock component {}. Error - {}", componentId, lockResult);
112             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
113             return result;
114         }
115
116         try {
117             if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) {
118                 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
119                 return result;
120             }
121
122             List<PropertyDefinition> properties = component.getProperties();
123
124             if(CollectionUtils.isEmpty(properties)) {
125                 properties = new ArrayList<>();
126             }
127
128             if(isPropertyExistInComponent(properties, propertyName)) {
129
130                 result =
131                     Either.right(componentsUtils.getResponseFormat(ActionStatus
132                         .PROPERTY_ALREADY_EXIST, propertyName));
133                 return result;
134
135             } else {
136
137                 Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache);
138                 if (allDataTypes.isRight()) {
139                     result = Either.right(allDataTypes.right().value());
140                     return result;
141                 }
142
143                 Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value();
144
145                 // validate property default values
146                 Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newPropertyDefinition, dataTypes);
147                 if (defaultValuesValidation.isRight()) {
148                     result = Either.right(defaultValuesValidation.right().value());
149                     return result;
150                 }
151                 // convert property
152                 ToscaPropertyType type = getType(newPropertyDefinition.getType());
153                 if (type != null) {
154                     PropertyValueConverter converter = type.getConverter();
155                     // get inner type
156                     String innerType = null;
157                     if (newPropertyDefinition != null) {
158                         SchemaDefinition schema = newPropertyDefinition.getSchema();
159                         if (schema != null) {
160                             PropertyDataDefinition prop = schema.getProperty();
161                             if (prop != null) {
162                                 innerType = prop.getType();
163                             }
164                         }
165                         String convertedValue = null;
166                         if (newPropertyDefinition.getDefaultValue() != null) {
167                             convertedValue = converter.convert(
168                                 newPropertyDefinition.getDefaultValue(), innerType, allDataTypes.left().value());
169                             newPropertyDefinition.setDefaultValue(convertedValue);
170                         }
171                     }
172                 }
173                 Either<PropertyDefinition, StorageOperationStatus> addPropertyEither =
174                     toscaOperationFacade
175                         .addPropertyToComponent(propertyName, newPropertyDefinition, component);
176
177                 if (addPropertyEither.isRight()) {
178                     log.info("Failed to add new property {}. Error - {}", componentId,
179                         addPropertyEither.right().value());
180                     result = Either.right(componentsUtils.getResponseFormat(ActionStatus
181                         .GENERAL_ERROR));
182                     return result;
183                 }
184             }
185
186             result = Either.left(new EntryData<>(propertyName, newPropertyDefinition));
187             return result;
188
189         } finally {
190             commitOrRollback(result);
191             // unlock component
192             graphLockOperation.unlockComponent(componentId, nodeType);
193         }
194
195     }
196
197     /**
198      * Get property of component
199      *
200      * @param componentId
201      * @param propertyId
202      * @param userId
203      * @return either properties or response format
204      */
205
206     public Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> getComponentProperty(String componentId, String propertyId, String userId) {
207
208         validateUserExists(userId, "create Component Instance", false);
209         // Get the resource from DB
210         Either<Component, StorageOperationStatus> status =
211             toscaOperationFacade.getToscaElement(componentId);
212         if (status.isRight()) {
213             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
214         }
215         Component component = status.left().value();
216         List<PropertyDefinition> properties = component.getProperties();
217         if(CollectionUtils.isEmpty(properties)) {
218             return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, ""));
219         }
220
221         for(PropertyDefinition property : properties) {
222             if(property.getUniqueId().equals(propertyId)) {
223                 return Either.left(new EntryData<>(property.getName(), property));
224             }
225         }
226         return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, ""));
227     }
228
229
230     public Either<List<PropertyDefinition>, ResponseFormat> getPropertiesList(String componentId,
231                                                                               String userId) {
232         validateUserExists(userId, "create Component Instance", false);
233
234         // Get the resource from DB
235         ComponentParametersView filter = new ComponentParametersView(true);
236         filter.setIgnoreProperties(false);
237         Either<Component, StorageOperationStatus> status =
238             toscaOperationFacade.getToscaElement(componentId);
239         if (status.isRight()) {
240             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
241         }
242         Component component = status.left().value();
243         List<PropertyDefinition> properties = component.getProperties();
244
245         return Either.left(properties);
246     }
247
248
249     /**
250      * delete property of component from graph
251      *
252      * @param componentId
253      * @param propertyId
254      * @param userId
255      * @return either properties or response format
256      */
257
258     public Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> deletePropertyFromComponent(String componentId, String propertyId, String userId) {
259
260         Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> result = null;
261
262         validateUserExists(userId, "delete Property", false);
263
264         // Get the resource from DB
265         Either<Component, StorageOperationStatus> getComponentRes = toscaOperationFacade.getToscaElement(componentId);
266         if (getComponentRes.isRight()) {
267             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
268             return result;
269         }
270         Component component = getComponentRes.left().value();
271         NodeTypeEnum nodeType = component.getComponentType().getNodeType();
272         StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType);
273         if (!lockResult.equals(StorageOperationStatus.OK)) {
274             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(),
275                     componentId);
276             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
277             return result;
278         }
279
280         try {
281             // verify that resource is checked-out and the user is the last
282             // updater
283             if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) {
284                 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
285                 return result;
286             }
287
288             // verify property exist in resource
289             Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty =
290                 getComponentProperty(componentId, propertyId, userId);
291             if (statusGetProperty.isRight()) {
292                 result = Either.right(statusGetProperty.right().value());
293                 return result;
294             }
295
296             Map.Entry<String, PropertyDefinition> propertyDefinitionEntry = statusGetProperty.left().value();
297
298             // verify that the property is not used by operation
299             if (isPropertyUsedByOperation(component, propertyDefinitionEntry.getValue())) {
300                 return Either.right(componentsUtils.getResponseFormat(ActionStatus
301                     .PROPERTY_USED_BY_OPERATION));
302             }
303
304             StorageOperationStatus status =
305                 toscaOperationFacade.deletePropertyOfComponent(component, propertyDefinitionEntry.getKey());
306             if (status != StorageOperationStatus.OK) {
307                 result = Either.right(componentsUtils.getResponseFormat(componentsUtils
308                     .convertFromStorageResponse(status), component.getName()));
309                 return result;
310             }
311             result = Either.left(propertyDefinitionEntry);
312             return result;
313
314         } finally {
315             commitOrRollback(result);
316             // unlock component
317             graphLockOperation.unlockComponent(componentId, nodeType);
318         }
319     }
320
321     public boolean isPropertyUsedByOperation(Component component,
322                                              PropertyDefinition propertyDefinitionEntry) {
323
324         // Component's own interfaces
325         Map<String, InterfaceDefinition> interfaces = component.getInterfaces();
326         if(MapUtils.isNotEmpty(interfaces)){
327           for(Map.Entry<String, InterfaceDefinition> interfaceEntry : interfaces.entrySet()) {
328             if (isPropertyExistInOperationInterface(propertyDefinitionEntry, interfaceEntry.getValue())) {
329               return true;
330             }
331           }
332         }
333
334         // Component's child's component interfaces
335         if(isPropertyUsedInCIInterfaces(component.getComponentInstancesInterfaces(), propertyDefinitionEntry)){
336             return true;
337         }
338
339         // Component's parent's component interfaces
340         Either<List<Component>, StorageOperationStatus> componentList = toscaOperationFacade.getParentComponents(component.getUniqueId());
341         if(componentList.isLeft()){
342             for (Component parentComponent : componentList.left().value()) {
343                 if(isPropertyUsedInCIInterfaces(parentComponent.getComponentInstancesInterfaces(), propertyDefinitionEntry)){
344                     return true;
345                 }
346             }
347         }
348
349         return false;
350     }
351
352     private boolean isPropertyUsedInCIInterfaces(Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces, PropertyDefinition propertyDefinitionEntry){
353         Optional<ComponentInstanceInterface> isPropertyExistInOperationInterface = Optional.empty();
354         if(MapUtils.isNotEmpty(componentInstanceInterfaces)){
355             isPropertyExistInOperationInterface = componentInstanceInterfaces.entrySet().stream()
356                     .flatMap(interfaceEntry -> interfaceEntry.getValue().stream())
357                     .filter(instanceInterface -> isPropertyExistInOperationInterface(propertyDefinitionEntry, instanceInterface))
358                     .findAny();
359         }
360         return isPropertyExistInOperationInterface.isPresent();
361     }
362
363     private boolean isPropertyExistInOperationInterface(PropertyDefinition propertyDefinition,
364                                                         InterfaceDefinition interfaceDefinition) {
365         Map<String, OperationDataDefinition> operations =
366             interfaceDefinition.getOperations();
367         for(Map.Entry<String, OperationDataDefinition> operationEntry : operations
368             .entrySet()) {
369             Optional<OperationInputDefinition> inputWithDeletedPropertyCandidate =
370                 getInputWithDeclaredProperty(propertyDefinition, operationEntry);
371
372             if(inputWithDeletedPropertyCandidate.isPresent()) {
373                 return true;
374             }
375         }
376         return false;
377     }
378
379     private Optional<OperationInputDefinition> getInputWithDeclaredProperty(PropertyDefinition propertyDefinition,
380                                                                             Map.Entry<String, OperationDataDefinition> operationEntry) {
381         ListDataDefinition<OperationInputDefinition> inputs =
382             operationEntry.getValue().getInputs();
383         List<OperationInputDefinition> operationInputsList =
384             Objects.isNull(inputs) ? null : inputs.getListToscaDataDefinition();
385
386         if(CollectionUtils.isEmpty(operationInputsList)) {
387             return Optional.empty();
388         }
389
390         return operationInputsList.stream().filter(input -> input.getInputId().equals(propertyDefinition.getUniqueId())
391                 || (input.getSourceProperty() != null && input.getSourceProperty().equals(propertyDefinition.getUniqueId()))).findAny();
392     }
393
394     /**
395      * update property
396      *
397      * @param componentId
398      * @param propertyId
399      * @param newPropertyDefinition
400      * @param userId
401      * @return either properties or response format
402      */
403
404     public Either<EntryData<String, PropertyDefinition>, ResponseFormat> updateComponentProperty(String componentId,
405                                                                         String propertyId,
406                                                                         PropertyDefinition newPropertyDefinition,
407                                                                         String userId) {
408
409         Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null;
410
411         Either<Component, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(
412                 componentId);
413         if (status.isRight()) {
414             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
415         }
416         Component component = status.left().value();
417         NodeTypeEnum nodeType = component.getComponentType().getNodeType();
418
419         if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) {
420             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
421         }
422
423         StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType);
424         if (!lockResult.equals(StorageOperationStatus.OK)) {
425             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(),
426                     componentId);
427             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
428             return result;
429         }
430
431         try {
432             Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty =
433                 getComponentProperty(componentId, propertyId, userId);
434             if (statusGetProperty.isRight()) {
435                 result = Either.right(statusGetProperty.right().value());
436                 return result;
437             }
438             String propertyName = statusGetProperty.left().value().getKey();
439
440             Either<PropertyDefinition, StorageOperationStatus> either =
441                 toscaOperationFacade.updatePropertyOfComponent(component, newPropertyDefinition);
442             if (either.isRight()) {
443                 result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(either.right().value()), component.getName()));
444                 return result;
445             }
446
447             EntryData<String, PropertyDefinition> property = new EntryData<>(propertyName, either.left().value());
448             result = Either.left(property);
449             return result;
450
451         } finally {
452             commitOrRollback(result);
453             graphLockOperation.unlockComponent(componentId, nodeType);
454         }
455
456     }
457
458     private boolean isPropertyExistInComponent(List<PropertyDefinition> properties, String propertyName) {
459         if(CollectionUtils.isEmpty(properties)) {
460             return false;
461         }
462
463         Optional<PropertyDefinition> propertyCandidate =
464             properties.stream().filter(property -> property.getName().equals(propertyName))
465                 .findAny();
466
467         return propertyCandidate.isPresent();
468     }
469
470     private boolean isPropertyExist(List<PropertyDefinition> properties, String resourceUid, String propertyName, String propertyType) {
471         boolean result = false;
472         if (!CollectionUtils.isEmpty(properties)) {
473             for (PropertyDefinition propertyDefinition : properties) {
474
475                 if ( propertyDefinition.getName().equals(propertyName) &&
476                     (propertyDefinition.getParentUniqueId().equals(resourceUid) || !propertyDefinition.getType().equals(propertyType)) ) {
477                     result = true;
478                     break;
479                 }
480             }
481         }
482         return result;
483     }
484
485     private Either<PropertyDefinition, StorageOperationStatus> handleProperty(PropertyDefinition newPropertyDefinition, Map<String, DataTypeDefinition> dataTypes) {
486
487         StorageOperationStatus validateAndUpdateProperty = validateAndUpdateProperty(newPropertyDefinition, dataTypes);
488         if (validateAndUpdateProperty != StorageOperationStatus.OK) {
489             return Either.right(validateAndUpdateProperty);
490         }
491
492         return Either.left(newPropertyDefinition);
493     }
494
495     private StorageOperationStatus validateAndUpdateProperty(IComplexDefaultValue propertyDefinition, Map<String, DataTypeDefinition> dataTypes) {
496
497         log.trace("Going to validate property type and value. {}", propertyDefinition);
498
499         String propertyType = propertyDefinition.getType();
500         String value = propertyDefinition.getDefaultValue();
501
502         ToscaPropertyType type = getType(propertyType);
503
504         if (type == null) {
505             DataTypeDefinition dataTypeDefinition = dataTypes.get(propertyType);
506             if (dataTypeDefinition == null) {
507                 log.debug("The type {} of property cannot be found.", propertyType);
508                 return StorageOperationStatus.INVALID_TYPE;
509             }
510             return validateAndUpdateComplexValue(propertyDefinition, propertyType, value, dataTypeDefinition, dataTypes);
511         }
512         String innerType;
513
514         Either<String, TitanOperationStatus> checkInnerType = getInnerType(type, propertyDefinition::getSchema);
515         if (checkInnerType.isRight()) {
516             return StorageOperationStatus.INVALID_TYPE;
517         }
518         innerType = checkInnerType.left().value();
519
520         log.trace("After validating property type {}", propertyType);
521
522         boolean isValidProperty = isValidValue(type, value, innerType, dataTypes);
523         if (!isValidProperty) {
524             log.info("The value {} of property from type {} is invalid", value, type);
525             return StorageOperationStatus.INVALID_VALUE;
526         }
527
528         PropertyValueConverter converter = type.getConverter();
529
530         if (isEmptyValue(value)) {
531             log.debug("Default value was not sent for property {}. Set default value to {}", propertyDefinition.getName(), EMPTY_VALUE);
532             propertyDefinition.setDefaultValue(EMPTY_VALUE);
533         } else if (!isEmptyValue(value)) {
534             String convertedValue = converter.convert(value, innerType, dataTypes);
535             propertyDefinition.setDefaultValue(convertedValue);
536         }
537         return StorageOperationStatus.OK;
538     }
539
540     private StorageOperationStatus validateAndUpdateComplexValue(IComplexDefaultValue propertyDefinition, String propertyType,
541                                                                  String value, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> dataTypes) {
542
543         ImmutablePair<JsonElement, Boolean> validateResult = dataTypeValidatorConverter.validateAndUpdate(value, dataTypeDefinition, dataTypes);
544
545         if (validateResult.right) {
546             log.debug("The value {} of property from type {} is invalid", propertyType, propertyType);
547             return StorageOperationStatus.INVALID_VALUE;
548         }
549
550         JsonElement jsonElement = validateResult.left;
551
552         log.trace("Going to update value in property definition {} {}" , propertyDefinition.getName() , jsonElement);
553
554         updateValue(propertyDefinition, jsonElement);
555
556         return StorageOperationStatus.OK;
557     }
558
559     private void updateValue(IComplexDefaultValue propertyDefinition, JsonElement jsonElement) {
560
561         propertyDefinition.setDefaultValue(getValueFromJsonElement(jsonElement));
562
563     }
564
565     @Override
566     protected String getValueFromJsonElement(JsonElement jsonElement) {
567         if (jsonElement == null || jsonElement.isJsonNull()) {
568             return EMPTY_VALUE;
569         }
570         if(jsonElement.toString().isEmpty()){
571             return "";
572         }
573         return jsonElement.toString();
574     }
575
576     private Either<String, TitanOperationStatus> getInnerType(ToscaPropertyType type, Supplier<SchemaDefinition> schemeGen) {
577         String innerType = null;
578         if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
579
580             SchemaDefinition def = schemeGen.get();
581             if (def == null) {
582                 log.debug("Schema doesn't exists for property of type {}", type);
583                 return Either.right(TitanOperationStatus.ILLEGAL_ARGUMENT);
584             }
585             PropertyDataDefinition propDef = def.getProperty();
586             if (propDef == null) {
587                 log.debug("Property in Schema Definition inside property of type {} doesn't exist", type);
588                 return Either.right(TitanOperationStatus.ILLEGAL_ARGUMENT);
589             }
590             innerType = propDef.getType();
591         }
592         return Either.left(innerType);
593     }
594
595     @Override
596     protected boolean isValidValue(ToscaPropertyType type, String value, String innerType, Map<String, DataTypeDefinition> dataTypes) {
597         if (isEmptyValue(value)) {
598             return true;
599         }
600         PropertyTypeValidator validator = type.getValidator();
601         return validator.isValid(value, innerType, dataTypes);
602     }
603
604     @Override
605     public boolean isEmptyValue(String value) {
606         return value == null;
607     }
608 }