Remove dead code
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / property / DefaultPropertyDeclarator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019 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.property;
22
23 import com.google.gson.Gson;
24 import fj.data.Either;
25 import org.apache.commons.collections.CollectionUtils;
26 import org.apache.commons.collections.MapUtils;
27 import org.apache.commons.lang.StringUtils;
28 import org.json.simple.JSONObject;
29 import org.openecomp.sdc.be.components.utils.PropertiesUtils;
30 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
31 import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
32 import org.openecomp.sdc.be.datatypes.elements.GetPolicyValueDataDefinition;
33 import org.openecomp.sdc.be.datatypes.elements.PropertiesOwner;
34 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
35 import org.openecomp.sdc.be.impl.ComponentsUtils;
36 import org.openecomp.sdc.be.model.CapabilityDefinition;
37 import org.openecomp.sdc.be.model.Component;
38 import org.openecomp.sdc.be.model.ComponentInstancePropInput;
39 import org.openecomp.sdc.be.model.IComponentInstanceConnectedElement;
40 import org.openecomp.sdc.be.model.InputDefinition;
41 import org.openecomp.sdc.be.model.PolicyDefinition;
42 import org.openecomp.sdc.be.model.PropertyDefinition;
43 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
44 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
45 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
46 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
47 import org.openecomp.sdc.common.log.wrappers.Logger;
48 import org.openecomp.sdc.exception.ResponseFormat;
49 import org.yaml.snakeyaml.Yaml;
50
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collection;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Objects;
59 import java.util.Optional;
60 import java.util.Set;
61 import java.util.stream.Collectors;
62
63 import static org.openecomp.sdc.common.api.Constants.GET_INPUT;
64 import static org.openecomp.sdc.common.api.Constants.GET_POLICY;
65
66 public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends PropertiesOwner, PROPERTYTYPE extends PropertyDataDefinition> implements PropertyDeclarator {
67
68     private static final Logger log = Logger.getLogger(DefaultPropertyDeclarator.class);
69     private static final short LOOP_PROTECTION_LEVEL = 10;
70     private static final String UNDERSCORE = "_";
71     private final Gson gson = new Gson();
72     private ComponentsUtils componentsUtils;
73     private PropertyOperation propertyOperation;
74     private static final String GET_INPUT_INDEX = "INDEX";
75
76     public DefaultPropertyDeclarator(ComponentsUtils componentsUtils, PropertyOperation propertyOperation) {
77         this.componentsUtils = componentsUtils;
78         this.propertyOperation = propertyOperation;
79     }
80
81     @Override
82     public Either<List<InputDefinition>, StorageOperationStatus> declarePropertiesAsInputs(Component component, String propertiesOwnerId, List<ComponentInstancePropInput> propsToDeclare) {
83         log.debug("#declarePropertiesAsInputs - declaring properties as inputs for component {} from properties owner {}", component.getUniqueId(), propertiesOwnerId);
84         return resolvePropertiesOwner(component, propertiesOwnerId)
85                 .map(propertyOwner -> declarePropertiesAsInputs(component, propertyOwner, propsToDeclare))
86                 .orElse(Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId)));
87     }
88
89     protected abstract PROPERTYTYPE createDeclaredProperty(PropertyDataDefinition prop);
90
91     protected abstract Either<?, StorageOperationStatus> updatePropertiesValues(Component component, String propertiesOwnerId, List<PROPERTYTYPE> properties);
92
93     protected abstract Optional<PROPERTYOWNER> resolvePropertiesOwner(Component component, String propertiesOwnerId);
94
95     protected abstract void addPropertiesListToInput(PROPERTYTYPE declaredProp, InputDefinition input);
96
97     @Override
98     public Either<List<PolicyDefinition>, StorageOperationStatus> declarePropertiesAsPolicies(Component component,
99             String propertiesOwnerId,
100             List<ComponentInstancePropInput> propsToDeclare) {
101         log.debug("#declarePropertiesAsPolicies - declaring properties as policies for component {} from properties owner {}", component.getUniqueId(), propertiesOwnerId);
102         return resolvePropertiesOwner(component, propertiesOwnerId)
103                        .map(propertyOwner -> declarePropertiesAsPolicies(component, propertyOwner, propsToDeclare))
104                        .orElse(Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId)));
105     }
106
107     @Override
108     public Either<InputDefinition, StorageOperationStatus> declarePropertiesAsListInput(Component component, String propertiesOwnerId, List<ComponentInstancePropInput> propsToDeclare, InputDefinition input) {
109         log.debug("#declarePropertiesAsListInput - declaring properties as inputs for component {} from properties owner {}", component.getUniqueId(), propertiesOwnerId);
110         Optional<PROPERTYOWNER> propertyOwner = resolvePropertiesOwner(component, propertiesOwnerId);
111         if (propertyOwner.isPresent()) {
112             return declarePropertiesAsListInput(component, propertyOwner.get(), propsToDeclare, input);
113         } else {
114             return Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId));
115         }
116     }
117
118     public StorageOperationStatus unDeclarePropertiesAsPolicies(Component component, PolicyDefinition policy) {
119         return StorageOperationStatus.OK;
120     }
121
122     private Either<List<PolicyDefinition>, StorageOperationStatus> declarePropertiesAsPolicies(Component component, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare) {
123         PropertiesDeclarationData policyProperties = createPoliciesAndOverridePropertiesValues(propertiesOwner.getUniqueId(), propertiesOwner, propsToDeclare);
124         return updatePropertiesValues(component, propertiesOwner.getUniqueId(), policyProperties.getPropertiesToUpdate())
125                        .left()
126                        .map(updatePropsRes -> policyProperties.getPoliciesToCreate());
127     }
128
129     private StorageOperationStatus onPropertiesOwnerNotFound(String componentId, String propertiesOwnerId) {
130         log.debug("#declarePropertiesAsInputs - properties owner {} was not found on component {}", propertiesOwnerId, componentId);
131         return StorageOperationStatus.NOT_FOUND;
132     }
133
134     private Either<List<InputDefinition>, StorageOperationStatus> declarePropertiesAsInputs(Component component, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare) {
135         PropertiesDeclarationData inputsProperties = createInputsAndOverridePropertiesValues(component, propertiesOwner, propsToDeclare);
136         return updatePropertiesValues(component, propertiesOwner.getUniqueId(), inputsProperties.getPropertiesToUpdate())
137                 .left()
138                 .map(updatePropsRes -> inputsProperties.getInputsToCreate());
139     }
140     private PropertiesDeclarationData createPoliciesAndOverridePropertiesValues(String componentId, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare) {
141         List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
142         List<PolicyDefinition> policies = new ArrayList<>();
143         propsToDeclare.forEach(property -> policies.add(declarePropertyPolicy(componentId, declaredProperties, property)));
144         return new PropertiesDeclarationData(null, policies, declaredProperties);
145     }
146
147     private PolicyDefinition declarePropertyPolicy(String componentId, List<PROPERTYTYPE> declaredProperties,
148             ComponentInstancePropInput propInput) {
149         PropertyDataDefinition prop = resolveProperty(declaredProperties, propInput);
150         propInput.setOwnerId(null);
151         propInput.setParentUniqueId(null);
152
153         PolicyDefinition policyDefinition = new PolicyDefinition(prop);
154         policyDefinition.setUniqueId(UniqueIdBuilder.buildPolicyUniqueId(componentId, prop.getName()));
155         policyDefinition.setInputPath(prop.getName());
156         policyDefinition.setInstanceUniqueId(componentId);
157         policyDefinition.setPropertyId(prop.getUniqueId());
158
159         changePropertyValueToGetPolicy(prop, policyDefinition);
160         PROPERTYTYPE declaredProperty = createDeclaredProperty(prop);
161
162
163         if(!declaredProperties.contains(declaredProperty)){
164             declaredProperties.add(declaredProperty);
165         }
166
167         return policyDefinition;
168     }
169
170     private void changePropertyValueToGetPolicy(PropertyDataDefinition prop, PolicyDefinition policyDefinition) {
171         JSONObject jsonObject = new JSONObject();
172
173         String origValue = Objects.isNull(prop.getValue()) ? prop.getDefaultValue() : prop.getValue();
174         jsonObject.put(GET_POLICY, null);
175         prop.setValue(jsonObject.toJSONString());
176         policyDefinition.setValue(jsonObject.toJSONString());
177
178         if(CollectionUtils.isEmpty(prop.getGetPolicyValues())){
179             prop.setGetPolicyValues(new ArrayList<>());
180         }
181         List<GetPolicyValueDataDefinition> getPolicyValues = prop.getGetPolicyValues();
182
183         GetPolicyValueDataDefinition getPolicyValueDataDefinition = new GetPolicyValueDataDefinition();
184         getPolicyValueDataDefinition.setPolicyId(policyDefinition.getUniqueId());
185         getPolicyValueDataDefinition.setPropertyName(prop.getName());
186
187         getPolicyValueDataDefinition.setOrigPropertyValue(origValue);
188
189         getPolicyValues.add(getPolicyValueDataDefinition);
190
191         policyDefinition.setGetPolicyValues(getPolicyValues);
192
193     }
194
195
196     private Either<InputDefinition, StorageOperationStatus> declarePropertiesAsListInput(Component component, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare, InputDefinition input) {
197         List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
198         for (ComponentInstancePropInput propInput : propsToDeclare) {
199             if (StringUtils.isNotEmpty(propInput.getPropertiesName()) && propInput.getInput() != null) {
200                 // sub-property in complex type is checked on UI. currently not supported.
201                 log.debug("skip propInput (propertiesName={}) currently not supported.", propInput.getPropertiesName());
202                 continue;
203             }
204             PROPERTYTYPE declaredProperty = createDeclaredProperty(propInput);
205
206             JSONObject jsonObject = new JSONObject();
207             jsonObject.put(GET_INPUT, Arrays.asList(input.getName(), GET_INPUT_INDEX, propInput.getName()));
208             declaredProperty.setValue(jsonObject.toJSONString());
209
210             GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
211             getInputValueDataDefinition.setInputId(input.getUniqueId());
212             getInputValueDataDefinition.setInputName(input.getName());
213             List<GetInputValueDataDefinition> getInputValues = declaredProperty.getGetInputValues();
214             if (getInputValues == null) {
215                 getInputValues = new ArrayList<>();
216                 declaredProperty.setGetInputValues(getInputValues);
217             }
218             getInputValues.add(getInputValueDataDefinition);
219
220             if (!declaredProperties.contains(declaredProperty)) {
221                 // Add property to the list if not contain in declareProperties.
222                 declaredProperties.add(declaredProperty);
223             }
224         }
225         return updatePropertiesValues(component, propertiesOwner.getUniqueId(), declaredProperties)
226                 .left().map(x -> input);
227     }
228
229     private PropertiesDeclarationData createInputsAndOverridePropertiesValues(Component component, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare) {
230         List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
231         List<InputDefinition> createdInputs = propsToDeclare.stream()
232                 .map(propInput -> declarePropertyInput(component, propertiesOwner, declaredProperties, propInput))
233                 .collect(Collectors.toList());
234         return new PropertiesDeclarationData(createdInputs, null, declaredProperties);
235     }
236
237     private InputDefinition declarePropertyInput(Component component, PROPERTYOWNER propertiesOwner, List<PROPERTYTYPE> declaredProperties, ComponentInstancePropInput propInput) {
238         PropertyDataDefinition prop = resolveProperty(declaredProperties, propInput);
239         InputDefinition inputDefinition = createInput(component, propertiesOwner, propInput, prop);
240         PROPERTYTYPE declaredProperty = createDeclaredProperty(prop);
241         if(!declaredProperties.contains(declaredProperty)){
242             declaredProperties.add(declaredProperty);
243         }
244         addPropertiesListToInput(declaredProperty, inputDefinition);
245         return inputDefinition;
246     }
247
248     private InputDefinition createInput(Component component, PROPERTYOWNER propertiesOwner,
249                                         ComponentInstancePropInput propInput, PropertyDataDefinition prop) {
250         String generatedInputPrefix = propertiesOwner.getNormalizedName();
251         if (propertiesOwner.getUniqueId().equals(propInput.getParentUniqueId())) {
252             //Creating input from property create on self using add property..Do not add the prefix
253             generatedInputPrefix = null;
254         }
255
256         Optional<CapabilityDefinition> propertyCapability = PropertiesUtils.getPropertyCapabilityOfChildInstance(propInput
257                 .getParentUniqueId(), component.getCapabilities());
258         if (propertyCapability.isPresent()) {
259             String capName = propertyCapability.get().getName();
260             if(capName.contains(".")) {
261                 capName = capName.replaceAll("\\.", UNDERSCORE);
262             }
263             generatedInputPrefix = generatedInputPrefix ==  null || generatedInputPrefix.isEmpty()?
264                     capName : generatedInputPrefix + UNDERSCORE + capName;
265         }
266
267         String generatedInputName = generateInputName(generatedInputPrefix, propInput);
268         log.debug("createInput: propOwner.uniqueId={}, propInput.parentUniqueId={}", propertiesOwner.getUniqueId(), propInput.getParentUniqueId());
269         return createInputFromProperty(component.getUniqueId(), propertiesOwner, generatedInputName, propInput, prop);
270     }
271
272     private String generateInputName(String inputName, ComponentInstancePropInput propInput) {
273         String declaredInputName;
274         String[] parsedPropNames = propInput.getParsedPropNames();
275
276         if(parsedPropNames != null){
277             declaredInputName = handleInputName(inputName, parsedPropNames);
278         } else {
279             String[] propName = {propInput.getName()};
280             declaredInputName = handleInputName(inputName, propName);
281         }
282
283         return declaredInputName;
284     }
285
286     private String handleInputName(String inputName, String[] parsedPropNames) {
287         StringBuilder prefix = new StringBuilder();
288         int startingIndex;
289
290         if(Objects.isNull(inputName)) {
291             prefix.append(parsedPropNames[0]);
292             startingIndex = 1;
293         } else {
294             prefix.append(inputName);
295             startingIndex = 0;
296         }
297
298         while(startingIndex < parsedPropNames.length){
299             prefix.append(UNDERSCORE);
300             prefix.append(parsedPropNames[startingIndex]);
301             startingIndex ++;
302         }
303
304         return prefix.toString();
305     }
306
307     private PropertyDataDefinition resolveProperty(List<PROPERTYTYPE> propertiesToCreate, ComponentInstancePropInput propInput) {
308         Optional<PROPERTYTYPE> resolvedProperty = propertiesToCreate.stream()
309                 .filter(p -> p.getName().equals(propInput.getName()))
310                 .findFirst();
311         return resolvedProperty.isPresent() ? resolvedProperty.get() : propInput;
312     }
313
314     InputDefinition createInputFromProperty(String componentId, PROPERTYOWNER propertiesOwner, String inputName, ComponentInstancePropInput propInput, PropertyDataDefinition prop) {
315         String propertiesName = propInput.getPropertiesName() ;
316         PropertyDefinition selectedProp = propInput.getInput();
317         String[] parsedPropNames = propInput.getParsedPropNames();
318         InputDefinition input;
319         boolean complexProperty = false;
320         if(propertiesName != null && !propertiesName.isEmpty() && selectedProp != null){
321             complexProperty = true;
322             input = new InputDefinition(selectedProp);
323             input.setDefaultValue(selectedProp.getValue());
324         }else{
325             input = new InputDefinition(prop);
326             input.setDefaultValue(prop.getValue());
327         }
328         input.setName(inputName);
329         input.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(componentId, input.getName()));
330         input.setInputPath(propertiesName);
331         input.setInstanceUniqueId(propertiesOwner.getUniqueId());
332         input.setPropertyId(propInput.getUniqueId());
333                 if (Objects.isNull(input.getSubPropertyInputPath())
334                                 || (Objects.nonNull(propertiesName)
335                                 && input.getSubPropertyInputPath().substring(input.getSubPropertyInputPath().lastIndexOf('#'))
336                                 .equals(propertiesName.substring(propertiesName.lastIndexOf('#'))))) {
337                         input.setParentPropertyType(propInput.getType());
338                         input.setSubPropertyInputPath(propertiesName);
339                 }
340
341         changePropertyValueToGetInputValue(inputName, parsedPropNames, input, prop, complexProperty);
342
343         if(prop instanceof IComponentInstanceConnectedElement) {
344             ((IComponentInstanceConnectedElement) prop)
345                 .setComponentInstanceId(propertiesOwner.getUniqueId());
346             ((IComponentInstanceConnectedElement) prop)
347                 .setComponentInstanceName(propertiesOwner.getName());
348         }
349         return input;
350     }
351
352     private void changePropertyValueToGetInputValue(String inputName, String[] parsedPropNames, InputDefinition input, PropertyDataDefinition prop, boolean complexProperty) {
353         JSONObject jsonObject = new JSONObject();
354         String value = prop.getValue();
355         if(value == null || value.isEmpty()){
356             if(complexProperty){
357
358                 jsonObject = createJSONValueForProperty(parsedPropNames.length -1, parsedPropNames, jsonObject, inputName);
359                 prop.setValue(jsonObject.toJSONString());
360
361             }else{
362
363                 jsonObject.put(GET_INPUT, input.getName());
364                 prop.setValue(jsonObject.toJSONString());
365
366             }
367
368         }else{
369
370             Object objValue =  new Yaml().load(value);
371             if( objValue instanceof Map || objValue  instanceof List){
372                 if(!complexProperty){
373                     jsonObject.put(GET_INPUT, input.getName());
374                     prop.setValue(jsonObject.toJSONString());
375
376
377                 }else{
378                     Map<String, Object> mappedToscaTemplate = (Map<String, Object>) objValue;
379                     createInputValue(mappedToscaTemplate, 1, parsedPropNames, inputName);
380
381                     String json = gson.toJson(mappedToscaTemplate);
382                     prop.setValue(json);
383
384                 }
385
386             }else{
387                 jsonObject.put(GET_INPUT, input.getName());
388                 prop.setValue(jsonObject.toJSONString());
389
390             }
391
392         }
393
394         if(CollectionUtils.isEmpty(prop.getGetInputValues())){
395             prop.setGetInputValues(new ArrayList<>());
396         }
397         List<GetInputValueDataDefinition> getInputValues = prop.getGetInputValues();
398
399         GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
400         getInputValueDataDefinition.setInputId(input.getUniqueId());
401         getInputValueDataDefinition.setInputName(input.getName());
402         getInputValues.add(getInputValueDataDefinition);
403     }
404
405     private  JSONObject createJSONValueForProperty (int i, String [] parsedPropNames, JSONObject ooj, String inputName){
406
407         while(i >= 1){
408             if( i == parsedPropNames.length -1){
409                 JSONObject jobProp = new JSONObject();
410                 jobProp.put(GET_INPUT, inputName);
411                 ooj.put(parsedPropNames[i], jobProp);
412                 i--;
413                 return createJSONValueForProperty (i, parsedPropNames, ooj, inputName);
414             }else{
415                 JSONObject res = new JSONObject();
416                 res.put(parsedPropNames[i], ooj);
417                 i --;
418                 res =  createJSONValueForProperty (i, parsedPropNames, res, inputName);
419                 return res;
420             }
421         }
422
423         return ooj;
424     }
425
426     private  Map<String, Object> createInputValue(Map<String, Object> lhm1, int index, String[] inputNames, String inputName){
427         while(index < inputNames.length){
428             if(lhm1.containsKey(inputNames[index])){
429                 Object value = lhm1.get(inputNames[index]);
430                 if (value instanceof Map){
431                     if(index == inputNames.length -1){
432                         ((Map) value).put(GET_INPUT, inputName);
433                         return (Map) value;
434
435                     }else{
436                         index++;
437                         return  createInputValue((Map)value, index, inputNames, inputName);
438                     }
439                 }else{
440                     Map<String, Object> jobProp = new HashMap<>();
441                     if(index == inputNames.length -1){
442                         jobProp.put(GET_INPUT, inputName);
443                         lhm1.put(inputNames[index], jobProp);
444                         return lhm1;
445                     }else{
446                         lhm1.put(inputNames[index], jobProp);
447                         index++;
448                         return  createInputValue(jobProp, index, inputNames, inputName);
449                     }
450                 }
451             }else{
452                 Map<String, Object> jobProp = new HashMap<>();
453                 lhm1.put(inputNames[index], jobProp);
454                 if(index == inputNames.length -1){
455                     jobProp.put(GET_INPUT, inputName);
456                     return jobProp;
457                 }else{
458                     index++;
459                     return  createInputValue(jobProp, index, inputNames, inputName);
460                 }
461             }
462         }
463         return lhm1;
464     }
465
466     private class PropertiesDeclarationData {
467         private List<InputDefinition> inputsToCreate;
468         private List<PolicyDefinition> policiesToCreate;
469         private List<PROPERTYTYPE> propertiesToUpdate;
470
471         PropertiesDeclarationData(List<InputDefinition> inputsToCreate, List<PolicyDefinition> policiesToCreate, List<PROPERTYTYPE> propertiesToUpdate) {
472             this.inputsToCreate = inputsToCreate;
473             this.policiesToCreate = policiesToCreate;
474             this.propertiesToUpdate = propertiesToUpdate;
475         }
476
477         List<InputDefinition> getInputsToCreate() {
478             return inputsToCreate;
479         }
480
481         public List<PolicyDefinition> getPoliciesToCreate() { return policiesToCreate; }
482
483         List<PROPERTYTYPE> getPropertiesToUpdate() {
484             return propertiesToUpdate;
485         }
486     }
487
488     Either<InputDefinition, ResponseFormat>  prepareValueBeforeDelete(InputDefinition inputForDelete, PropertyDataDefinition inputValue, List<String> pathOfComponentInstances) {
489         Either<InputDefinition, ResponseFormat> deleteEither = prepareValueBeforeDelete(inputForDelete, inputValue);
490
491         Either<String, JanusGraphOperationStatus> findDefaultValue = propertyOperation
492             .findDefaultValueFromSecondPosition(pathOfComponentInstances, inputValue.getUniqueId(),
493                 (String) inputValue.getDefaultValue());
494         if (findDefaultValue.isRight()) {
495             deleteEither = Either.right(componentsUtils.getResponseFormat(componentsUtils
496                 .convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(findDefaultValue.right().value()))));
497             return deleteEither;
498
499         }
500         String defaultValue = findDefaultValue.left().value();
501         inputValue.setDefaultValue(defaultValue);
502         log.debug("The returned default value in ResourceInstanceProperty is {}", defaultValue);
503         return deleteEither;
504     }
505
506     Either<InputDefinition, ResponseFormat>  prepareValueBeforeDeleteOfCapProp(InputDefinition inputForDelete,
507                                                                                PropertyDataDefinition inputValue) {
508         Either<InputDefinition, ResponseFormat> deleteEither = prepareValueBeforeDelete(inputForDelete, inputValue);
509         inputValue.setDefaultValue(inputForDelete.getDefaultValue());
510         log.debug("The returned default value in ResourceInstanceProperty is {}", inputForDelete.getDefaultValue());
511         return deleteEither;
512     }
513
514     private Either<InputDefinition, ResponseFormat> prepareValueBeforeDelete(InputDefinition inputForDelete,
515                                                                              PropertyDataDefinition inputValue) {
516         Either<InputDefinition, ResponseFormat> deleteEither = Either.left(inputForDelete);
517         String value = inputValue.getValue();
518         Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(value);
519
520         resetInputName(mappedToscaTemplate, inputForDelete.getName());
521
522         value = "";
523         if (!mappedToscaTemplate.isEmpty()) {
524             Either result = cleanNestedMap(mappedToscaTemplate, true);
525             Map modifiedMappedToscaTemplate = mappedToscaTemplate;
526             if (result.isLeft()) {
527                 modifiedMappedToscaTemplate = (Map) result.left().value();
528             } else {
529                 log.warn("Map cleanup failed -> " + result.right().value()
530                         .toString());    //continue, don't break operation
531             }
532             value = gson.toJson(modifiedMappedToscaTemplate);
533         }
534         inputValue.setValue(value);
535
536
537         List<GetInputValueDataDefinition> getInputsValues = inputValue.getGetInputValues();
538         if (getInputsValues != null && !getInputsValues.isEmpty()) {
539             Optional<GetInputValueDataDefinition> op =
540                     getInputsValues.stream().filter(gi -> gi.getInputId().equals(inputForDelete.getUniqueId()))
541                             .findAny();
542             op.ifPresent(getInputsValues::remove);
543         }
544         inputValue.setGetInputValues(getInputsValues);
545         return deleteEither;
546     }
547
548     private void resetInputName(Map<String, Object> lhm1, String inputName){
549         for (Map.Entry<String, Object> entry : lhm1.entrySet()) {
550             String key = entry.getKey();
551             Object value = entry.getValue();
552             if (value instanceof String && ((String) value).equalsIgnoreCase(inputName) && key.equals(GET_INPUT)) {
553                 lhm1.remove(key);
554             } else if (value instanceof Map) {
555                 Map<String, Object> subMap = (Map<String, Object>)value;
556                 resetInputName(subMap, inputName);
557             } else if (value instanceof List && ((List) value).contains(inputName) && key.equals(GET_INPUT)) {
558                 lhm1.remove(key);
559             }
560         }
561     }
562
563     private Either cleanNestedMap( Map mappedToscaTemplate , boolean deepClone  ){
564         if (MapUtils.isNotEmpty( mappedToscaTemplate ) ){
565             if (deepClone){
566                 if (!(mappedToscaTemplate instanceof HashMap))
567                     return Either.right("expecting mappedToscaTemplate as HashMap ,recieved "+ mappedToscaTemplate.getClass().getSimpleName() );
568                 else
569                     mappedToscaTemplate = (HashMap)((HashMap) mappedToscaTemplate).clone();
570             }
571             return Either.left( (Map) cleanEmptyNestedValuesInMap( mappedToscaTemplate , LOOP_PROTECTION_LEVEL ) );
572         }
573         else {
574             log.debug("mappedToscaTemplate is empty ");
575             return Either.right("mappedToscaTemplate is empty ");
576         }
577     }
578
579     /*        Mutates the object
580      *        Tail recurse -> traverse the tosca elements and remove nested empty map properties
581      *        this only handles nested maps, other objects are left untouched (even a Set containing a map) since behaviour is unexpected
582      *
583      *        @param  toscaElement - expected map of tosca values
584      *        @return mutated @param toscaElement , where empty maps are deleted , return null for empty map.
585      **/
586     private Object cleanEmptyNestedValuesInMap(Object toscaElement , short loopProtectionLevel ){
587         if (loopProtectionLevel<=0 || toscaElement==null || !(toscaElement instanceof  Map))
588             return toscaElement;
589         if ( MapUtils.isNotEmpty( (Map)toscaElement ) ) {
590             Object ret;
591             Set<Object> keysToRemove = new HashSet<>();                                                                 // use different set to avoid ConcurrentModificationException
592             for( Object key : ((Map)toscaElement).keySet() ) {
593                 Object value = ((Map) toscaElement).get(key);
594                 ret = cleanEmptyNestedValuesInMap(value , --loopProtectionLevel );
595                 if ( ret == null )
596                     keysToRemove.add(key);
597             }
598             Collection set = ((Map) toscaElement).keySet();
599             if (CollectionUtils.isNotEmpty(set))
600                 set.removeAll(keysToRemove);
601
602             if ( isEmptyNestedMap(toscaElement) )
603                 return null;
604         }
605         else
606             return null;
607         return toscaElement;
608     }
609
610     //@returns true iff map nested maps are all empty
611     //ignores other collection objects
612     private boolean isEmptyNestedMap(Object element){
613         boolean isEmpty = true;
614         if (element != null){
615             if ( element instanceof Map ){
616                 if (MapUtils.isEmpty((Map)element))
617                     isEmpty = true;
618                 else
619                 {
620                     for( Object key : ((Map)(element)).keySet() ){
621                         Object value =  ((Map)(element)).get(key);
622                         isEmpty &= isEmptyNestedMap( value );
623                     }
624                 }
625             } else {
626                 isEmpty = false;
627             }
628         }
629         return isEmpty;
630     }
631
632 }