Fix import service with component inst interfaces
[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 package org.openecomp.sdc.be.components.impl;
21
22 import com.google.gson.JsonElement;
23 import fj.data.Either;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Optional;
29 import org.apache.commons.collections.CollectionUtils;
30 import org.apache.commons.collections.MapUtils;
31 import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
32 import org.openecomp.sdc.be.config.BeEcompErrorManager;
33 import org.openecomp.sdc.be.dao.api.ActionStatus;
34 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
35 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
36 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
37 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
38 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
39 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
40 import org.openecomp.sdc.be.model.Component;
41 import org.openecomp.sdc.be.model.ComponentInstanceInterface;
42 import org.openecomp.sdc.be.model.ComponentParametersView;
43 import org.openecomp.sdc.be.model.DataTypeDefinition;
44 import org.openecomp.sdc.be.model.InterfaceDefinition;
45 import org.openecomp.sdc.be.model.PropertyDefinition;
46 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
47 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
48 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ToscaOperationException;
49 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
50 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
51 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
52 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
53 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
54 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
55 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
56 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
57 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
58 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
59 import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator;
60 import org.openecomp.sdc.be.resources.data.EntryData;
61 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
62 import org.openecomp.sdc.common.log.wrappers.Logger;
63 import org.openecomp.sdc.exception.ResponseFormat;
64 import org.springframework.beans.factory.annotation.Autowired;
65
66 @org.springframework.stereotype.Component("propertyBusinessLogic")
67 public class PropertyBusinessLogic extends BaseBusinessLogic {
68
69     private static final String CREATE_PROPERTY = "CreateProperty";
70     private static final Logger log = Logger.getLogger(PropertyBusinessLogic.class);
71     private static final String EMPTY_VALUE = null;
72
73     @Autowired
74     public PropertyBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
75                                  IGroupTypeOperation groupTypeOperation, InterfaceOperation interfaceOperation,
76                                  InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsOperations artifactToscaOperation) {
77         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
78             artifactToscaOperation);
79     }
80
81     /**
82      * Create new property on component in graph
83      *
84      * @param componentId
85      * @param newPropertyDefinition
86      * @param userId
87      * @return either properties or response format
88      */
89     public Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyToComponent(String componentId,
90                                                                                                 PropertyDefinition newPropertyDefinition,
91                                                                                                 String userId) {
92         Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null;
93         validateUserExists(userId);
94         Either<Component, StorageOperationStatus> serviceElement = toscaOperationFacade.getToscaElement(componentId);
95         if (serviceElement.isRight()) {
96             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
97             return result;
98         }
99         Component component = serviceElement.left().value();
100         NodeTypeEnum nodeType = component.getComponentType().getNodeType();
101         StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType);
102         if (!lockResult.equals(StorageOperationStatus.OK)) {
103             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(), componentId);
104             log.info("Failed to lock component {}. Error - {}", componentId, lockResult);
105             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
106             return result;
107         }
108         try {
109             final String propertyName = newPropertyDefinition.getName();
110             if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) {
111                 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
112                 return result;
113             }
114             List<PropertyDefinition> properties = component.getProperties();
115             if (CollectionUtils.isEmpty(properties)) {
116                 properties = new ArrayList<>();
117             }
118             if (isPropertyExistInComponent(properties, propertyName)) {
119                 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_ALREADY_EXIST, propertyName));
120                 return result;
121             } else {
122                 Map<String, DataTypeDefinition> allDataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
123                 // validate property default values
124                 Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newPropertyDefinition, allDataTypes);
125                 if (defaultValuesValidation.isRight()) {
126                     result = Either.right(defaultValuesValidation.right().value());
127                     return result;
128                 }
129                 // convert property
130                 ToscaPropertyType type = getType(newPropertyDefinition.getType());
131                 if (type != null) {
132                     PropertyValueConverter converter = type.getConverter();
133                     // get inner type
134                     String innerType = null;
135                     SchemaDefinition schema = newPropertyDefinition.getSchema();
136                     if (schema != null) {
137                         PropertyDataDefinition prop = schema.getProperty();
138                         if (prop != null) {
139                             innerType = prop.getType();
140                         }
141                     }
142                     if (newPropertyDefinition.getDefaultValue() != null) {
143                         final String convertedValue = converter.convert(newPropertyDefinition.getDefaultValue(), innerType, allDataTypes);
144                         newPropertyDefinition.setDefaultValue(convertedValue);
145                     }
146                 }
147                 Either<PropertyDefinition, StorageOperationStatus> addPropertyEither = toscaOperationFacade
148                     .addPropertyToComponent(newPropertyDefinition, component);
149                 if (addPropertyEither.isRight()) {
150                     log.info("Failed to add new property {}. Error - {}", componentId, addPropertyEither.right().value());
151                     result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
152                     return result;
153                 }
154             }
155             result = Either.left(new EntryData<>(propertyName, newPropertyDefinition));
156             return result;
157         } finally {
158             commitOrRollback(result);
159             // unlock component
160             graphLockOperation.unlockComponent(componentId, nodeType);
161         }
162     }
163
164     /**
165      * Copies a list of properties to a component.
166      *
167      * @param component            the component to add the copied properties
168      * @param propertiesToCopyList the properties to be copied
169      * @return the updated component with the copied properties.
170      * @throws ToscaOperationException when a problem happens during the copy operation
171      */
172     public Component copyPropertyToComponent(final Component component, final List<PropertyDefinition> propertiesToCopyList)
173         throws ToscaOperationException {
174         return copyPropertyToComponent(component, propertiesToCopyList, true);
175     }
176
177     /**
178      * Copies a list of properties to a component.
179      *
180      * @param component            the component to add the copied properties
181      * @param propertiesToCopyList the properties to be copied
182      * @param refreshComponent     refresh the component from database after update
183      * @return the component refreshed from database if refreshComponent is {@code true}, the same component reference otherwise
184      * @throws ToscaOperationException when a problem happens during the copy operation
185      */
186     public Component copyPropertyToComponent(final Component component, final List<PropertyDefinition> propertiesToCopyList,
187                                              final boolean refreshComponent) throws ToscaOperationException {
188         if (CollectionUtils.isEmpty(propertiesToCopyList)) {
189             return component;
190         }
191         for (final PropertyDefinition propertyDefinition : propertiesToCopyList) {
192             copyPropertyToComponent(component, propertyDefinition);
193         }
194         if (refreshComponent) {
195             return toscaOperationFacade.getToscaElement(component.getUniqueId()).left().value();
196         }
197         return component;
198     }
199
200     /**
201      * Copies one property to a component.
202      *
203      * @param component          the component to add the copied property
204      * @param propertyDefinition the property to be copied
205      * @throws ToscaOperationException when a problem happens during the copy operation
206      */
207     private void copyPropertyToComponent(final Component component, final PropertyDefinition propertyDefinition) throws ToscaOperationException {
208         final PropertyDefinition copiedPropertyDefinition = new PropertyDefinition(propertyDefinition);
209         final String componentId = component.getUniqueId();
210         final String propertyName = copiedPropertyDefinition.getName();
211         copiedPropertyDefinition.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(componentId, propertyName));
212         copiedPropertyDefinition.setParentUniqueId(componentId);
213         final Either<PropertyDefinition, StorageOperationStatus> operationResult = toscaOperationFacade
214             .addPropertyToComponent(copiedPropertyDefinition, component);
215         if (operationResult.isRight()) {
216             final String error = String
217                 .format("Failed to add copied property '%s' to component '%s'. Operation status: '%s'", propertyDefinition.getUniqueId(), componentId,
218                     operationResult.right().value());
219             log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, PropertyBusinessLogic.class.getName(), "catalog-be", error);
220             throw new ToscaOperationException(error, operationResult.right().value());
221         }
222     }
223
224     /**
225      * Get property of component
226      *
227      * @param componentId
228      * @param propertyId
229      * @param userId
230      * @return either properties or response format
231      */
232     public Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> getComponentProperty(String componentId, String propertyId, String userId) {
233         validateUserExists(userId);
234         // Get the resource from DB
235         Either<Component, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(componentId);
236         if (status.isRight()) {
237             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
238         }
239         Component component = status.left().value();
240         List<PropertyDefinition> properties = component.getProperties();
241         if (CollectionUtils.isEmpty(properties)) {
242             return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, ""));
243         }
244         for (PropertyDefinition property : properties) {
245             if (property.getUniqueId().equals(propertyId)) {
246                 return Either.left(new EntryData<>(property.getName(), property));
247             }
248         }
249         return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, ""));
250     }
251
252     public Either<List<PropertyDefinition>, ResponseFormat> getPropertiesList(String componentId, String userId) {
253         validateUserExists(userId);
254         // Get the resource from DB
255         ComponentParametersView filter = new ComponentParametersView(true);
256         filter.setIgnoreProperties(false);
257         Either<Component, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(componentId);
258         if (status.isRight()) {
259             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
260         }
261         Component component = status.left().value();
262         List<PropertyDefinition> properties = component.getProperties();
263         return Either.left(properties);
264     }
265
266     /**
267      * delete property of component from graph
268      *
269      * @param componentId
270      * @param propertyId
271      * @param userId
272      * @return either properties or response format
273      */
274     public Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> deletePropertyFromComponent(String componentId, String propertyId,
275                                                                                                      String userId) {
276         Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> result = null;
277         validateUserExists(userId);
278         // Get the resource from DB
279         Either<Component, StorageOperationStatus> getComponentRes = toscaOperationFacade.getToscaElement(componentId);
280         if (getComponentRes.isRight()) {
281             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
282             return result;
283         }
284         Component component = getComponentRes.left().value();
285         NodeTypeEnum nodeType = component.getComponentType().getNodeType();
286         StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType);
287         if (!lockResult.equals(StorageOperationStatus.OK)) {
288             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(), componentId);
289             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
290             return result;
291         }
292         try {
293             // verify that resource is checked-out and the user is the last
294
295             // updater
296             if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) {
297                 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
298                 return result;
299             }
300             // verify property exist in resource
301             Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty = getComponentProperty(componentId, propertyId, userId);
302             if (statusGetProperty.isRight()) {
303                 result = Either.right(statusGetProperty.right().value());
304                 return result;
305             }
306             Map.Entry<String, PropertyDefinition> propertyDefinitionEntry = statusGetProperty.left().value();
307             // verify that the property is not used by operation
308             if (isPropertyUsedByOperation(component, propertyDefinitionEntry.getValue())) {
309                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_USED_BY_OPERATION));
310             }
311             StorageOperationStatus status = toscaOperationFacade.deletePropertyOfComponent(component, propertyDefinitionEntry.getKey());
312             if (status != StorageOperationStatus.OK) {
313                 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status), component.getName()));
314                 return result;
315             }
316             result = Either.left(propertyDefinitionEntry);
317             return result;
318         } finally {
319             commitOrRollback(result);
320             // unlock component
321             graphLockOperation.unlockComponent(componentId, nodeType);
322         }
323     }
324
325     public boolean isPropertyUsedByOperation(Component component, PropertyDefinition propertyDefinitionEntry) {
326         // Component's own interfaces
327         Map<String, InterfaceDefinition> interfaces = component.getInterfaces();
328         if (MapUtils.isNotEmpty(interfaces)) {
329             for (Map.Entry<String, InterfaceDefinition> interfaceEntry : interfaces.entrySet()) {
330                 if (isPropertyExistInOperationInterface(propertyDefinitionEntry, interfaceEntry.getValue())) {
331                     return true;
332                 }
333             }
334         }
335         // Component's child's component interfaces
336         if (isPropertyUsedInCIInterfaces(component.getComponentInstancesInterfaces(), propertyDefinitionEntry)) {
337             return true;
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         return false;
349     }
350
351     private boolean isPropertyUsedInCIInterfaces(Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces,
352                                                  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)).findAny();
358         }
359         return isPropertyExistInOperationInterface.isPresent();
360     }
361
362     private boolean isPropertyExistInOperationInterface(PropertyDefinition propertyDefinition, InterfaceDefinition interfaceDefinition) {
363         Map<String, OperationDataDefinition> operations = interfaceDefinition.getOperations();
364         for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
365             Optional<OperationInputDefinition> inputWithDeletedPropertyCandidate = getInputWithDeclaredProperty(propertyDefinition, operationEntry);
366             if (inputWithDeletedPropertyCandidate.isPresent()) {
367                 return true;
368             }
369         }
370         return false;
371     }
372
373     private Optional<OperationInputDefinition> getInputWithDeclaredProperty(PropertyDefinition propertyDefinition,
374                                                                             Map.Entry<String, OperationDataDefinition> operationEntry) {
375         ListDataDefinition<OperationInputDefinition> inputs = operationEntry.getValue().getInputs();
376         List<OperationInputDefinition> operationInputsList = Objects.isNull(inputs) ? null : inputs.getListToscaDataDefinition();
377         if (CollectionUtils.isEmpty(operationInputsList)) {
378             return Optional.empty();
379         }
380         return operationInputsList.stream().filter(
381             input -> input.getInputId().equals(propertyDefinition.getUniqueId()) || (input.getSourceProperty() != null && input.getSourceProperty()
382                 .equals(propertyDefinition.getUniqueId()))).findAny();
383     }
384
385     /**
386      * update property
387      *
388      * @param componentId
389      * @param propertyId
390      * @param newPropertyDefinition
391      * @param userId
392      * @return either properties or response format
393      */
394     public Either<EntryData<String, PropertyDefinition>, ResponseFormat> updateComponentProperty(String componentId, String propertyId,
395                                                                                                  PropertyDefinition newPropertyDefinition,
396                                                                                                  String userId) {
397         Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null;
398         Either<Component, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(componentId);
399         if (status.isRight()) {
400             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
401         }
402         Component component = status.left().value();
403         NodeTypeEnum nodeType = component.getComponentType().getNodeType();
404         if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) {
405             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
406         }
407         StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType);
408         if (!lockResult.equals(StorageOperationStatus.OK)) {
409             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(), componentId);
410             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
411             return result;
412         }
413         try {
414             Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty = getComponentProperty(componentId, propertyId, userId);
415             if (statusGetProperty.isRight()) {
416                 result = Either.right(statusGetProperty.right().value());
417                 return result;
418             }
419             String propertyName = statusGetProperty.left().value().getKey();
420             Either<PropertyDefinition, StorageOperationStatus> either = toscaOperationFacade
421                 .updatePropertyOfComponent(component, newPropertyDefinition);
422             if (either.isRight()) {
423                 result = Either.right(componentsUtils
424                     .getResponseFormatByResource(componentsUtils.convertFromStorageResponse(either.right().value()), component.getName()));
425                 return result;
426             }
427             EntryData<String, PropertyDefinition> property = new EntryData<>(propertyName, either.left().value());
428             result = Either.left(property);
429             return result;
430         } finally {
431             commitOrRollback(result);
432             graphLockOperation.unlockComponent(componentId, nodeType);
433         }
434     }
435
436     /**
437      * Finds a component by id,
438      *
439      * @param componentId the component id to find
440      * @return an Optional<Component> if the component with given id was found, otherwise Optional.empty()
441      * @throws BusinessLogicException when a problem happens during the find operation
442      */
443     public Optional<Component> findComponentById(final String componentId) throws BusinessLogicException {
444         final Either<Component, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(componentId);
445         if (status.isRight()) {
446             final StorageOperationStatus operationStatus = status.right().value();
447             if (operationStatus == StorageOperationStatus.NOT_FOUND) {
448                 return Optional.empty();
449             }
450             final ResponseFormat responseFormat = componentsUtils.getResponseFormat(operationStatus);
451             throw new BusinessLogicException(responseFormat);
452         }
453         return Optional.ofNullable(status.left().value());
454     }
455
456     /**
457      * Updates a component property.
458      *
459      * @param componentId        the component id that owns the property
460      * @param propertyDefinition the existing property to update
461      * @return the updated property
462      * @throws BusinessLogicException if the component was not found or if there was a problem during the update operation.
463      */
464     public PropertyDefinition updateComponentProperty(final String componentId, final PropertyDefinition propertyDefinition)
465         throws BusinessLogicException {
466         final Component component = findComponentById(componentId).orElse(null);
467         if (component == null) {
468             throw new BusinessLogicException(componentsUtils.getResponseFormatByResource(ActionStatus.RESOURCE_NOT_FOUND, componentId));
469         }
470         final Either<PropertyDefinition, StorageOperationStatus> updateResultEither = toscaOperationFacade
471             .updatePropertyOfComponent(component, propertyDefinition);
472         if (updateResultEither.isRight()) {
473             final ResponseFormat responseFormat = componentsUtils
474                 .getResponseFormatByResource(componentsUtils.convertFromStorageResponse(updateResultEither.right().value()), component.getName());
475             throw new BusinessLogicException(responseFormat);
476         }
477         return updateResultEither.left().value();
478     }
479
480     private boolean isPropertyExistInComponent(List<PropertyDefinition> properties, String propertyName) {
481         if (CollectionUtils.isEmpty(properties)) {
482             return false;
483         }
484         Optional<PropertyDefinition> propertyCandidate = properties.stream().filter(property -> property.getName().equals(propertyName)).findAny();
485         return propertyCandidate.isPresent();
486     }
487
488     @Override
489     protected String getValueFromJsonElement(JsonElement jsonElement) {
490         if (jsonElement == null || jsonElement.isJsonNull()) {
491             return EMPTY_VALUE;
492         }
493         if (jsonElement.toString().isEmpty()) {
494             return "";
495         }
496         return jsonElement.toString();
497     }
498
499     @Override
500     protected boolean isValidValue(ToscaPropertyType type, String value, String innerType, Map<String, DataTypeDefinition> dataTypes) {
501         if (isEmptyValue(value)) {
502             return true;
503         }
504         PropertyTypeValidator validator = type.getValidator();
505         return validator.isValid(value, innerType, dataTypes);
506     }
507
508     @Override
509     public boolean isEmptyValue(String value) {
510         return value == null;
511     }
512 }