2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.be.components.property;
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;
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;
58 import java.util.Objects;
59 import java.util.Optional;
61 import java.util.stream.Collectors;
63 import static org.openecomp.sdc.common.api.Constants.GET_INPUT;
64 import static org.openecomp.sdc.common.api.Constants.GET_POLICY;
66 public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends PropertiesOwner, PROPERTYTYPE extends PropertyDataDefinition> implements PropertyDeclarator {
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";
76 public DefaultPropertyDeclarator(ComponentsUtils componentsUtils, PropertyOperation propertyOperation) {
77 this.componentsUtils = componentsUtils;
78 this.propertyOperation = propertyOperation;
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)));
89 protected abstract PROPERTYTYPE createDeclaredProperty(PropertyDataDefinition prop);
91 protected abstract Either<?, StorageOperationStatus> updatePropertiesValues(Component component, String propertiesOwnerId, List<PROPERTYTYPE> properties);
93 protected abstract Optional<PROPERTYOWNER> resolvePropertiesOwner(Component component, String propertiesOwnerId);
95 protected abstract void addPropertiesListToInput(PROPERTYTYPE declaredProp, InputDefinition input);
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)));
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);
114 return Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId));
118 public StorageOperationStatus unDeclarePropertiesAsPolicies(Component component, PolicyDefinition policy) {
119 return StorageOperationStatus.OK;
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())
126 .map(updatePropsRes -> policyProperties.getPoliciesToCreate());
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;
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())
138 .map(updatePropsRes -> inputsProperties.getInputsToCreate());
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);
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);
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());
159 changePropertyValueToGetPolicy(prop, policyDefinition);
160 PROPERTYTYPE declaredProperty = createDeclaredProperty(prop);
163 if(!declaredProperties.contains(declaredProperty)){
164 declaredProperties.add(declaredProperty);
167 return policyDefinition;
170 private void changePropertyValueToGetPolicy(PropertyDataDefinition prop, PolicyDefinition policyDefinition) {
171 JSONObject jsonObject = new JSONObject();
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());
178 if(CollectionUtils.isEmpty(prop.getGetPolicyValues())){
179 prop.setGetPolicyValues(new ArrayList<>());
181 List<GetPolicyValueDataDefinition> getPolicyValues = prop.getGetPolicyValues();
183 GetPolicyValueDataDefinition getPolicyValueDataDefinition = new GetPolicyValueDataDefinition();
184 getPolicyValueDataDefinition.setPolicyId(policyDefinition.getUniqueId());
185 getPolicyValueDataDefinition.setPropertyName(prop.getName());
187 getPolicyValueDataDefinition.setOrigPropertyValue(origValue);
189 getPolicyValues.add(getPolicyValueDataDefinition);
191 policyDefinition.setGetPolicyValues(getPolicyValues);
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());
204 PROPERTYTYPE declaredProperty = createDeclaredProperty(propInput);
206 JSONObject jsonObject = new JSONObject();
207 jsonObject.put(GET_INPUT, Arrays.asList(input.getName(), GET_INPUT_INDEX, propInput.getName()));
208 declaredProperty.setValue(jsonObject.toJSONString());
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);
218 getInputValues.add(getInputValueDataDefinition);
220 if (!declaredProperties.contains(declaredProperty)) {
221 // Add property to the list if not contain in declareProperties.
222 declaredProperties.add(declaredProperty);
225 return updatePropertiesValues(component, propertiesOwner.getUniqueId(), declaredProperties)
226 .left().map(x -> input);
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);
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);
244 addPropertiesListToInput(declaredProperty, inputDefinition);
245 return inputDefinition;
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;
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);
263 generatedInputPrefix = generatedInputPrefix == null || generatedInputPrefix.isEmpty()?
264 capName : generatedInputPrefix + UNDERSCORE + capName;
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);
272 private String generateInputName(String inputName, ComponentInstancePropInput propInput) {
273 String declaredInputName;
274 String[] parsedPropNames = propInput.getParsedPropNames();
276 if(parsedPropNames != null){
277 declaredInputName = handleInputName(inputName, parsedPropNames);
279 String[] propName = {propInput.getName()};
280 declaredInputName = handleInputName(inputName, propName);
283 return declaredInputName;
286 private String handleInputName(String inputName, String[] parsedPropNames) {
287 StringBuilder prefix = new StringBuilder();
290 if(Objects.isNull(inputName)) {
291 prefix.append(parsedPropNames[0]);
294 prefix.append(inputName);
298 while(startingIndex < parsedPropNames.length){
299 prefix.append(UNDERSCORE);
300 prefix.append(parsedPropNames[startingIndex]);
304 return prefix.toString();
307 private PropertyDataDefinition resolveProperty(List<PROPERTYTYPE> propertiesToCreate, ComponentInstancePropInput propInput) {
308 Optional<PROPERTYTYPE> resolvedProperty = propertiesToCreate.stream()
309 .filter(p -> p.getName().equals(propInput.getName()))
311 return resolvedProperty.isPresent() ? resolvedProperty.get() : propInput;
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());
325 input = new InputDefinition(prop);
326 input.setDefaultValue(prop.getValue());
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);
341 changePropertyValueToGetInputValue(inputName, parsedPropNames, input, prop, complexProperty);
343 if(prop instanceof IComponentInstanceConnectedElement) {
344 ((IComponentInstanceConnectedElement) prop)
345 .setComponentInstanceId(propertiesOwner.getUniqueId());
346 ((IComponentInstanceConnectedElement) prop)
347 .setComponentInstanceName(propertiesOwner.getName());
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()){
358 jsonObject = createJSONValueForProperty(parsedPropNames.length -1, parsedPropNames, jsonObject, inputName);
359 prop.setValue(jsonObject.toJSONString());
363 jsonObject.put(GET_INPUT, input.getName());
364 prop.setValue(jsonObject.toJSONString());
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());
378 Map<String, Object> mappedToscaTemplate = (Map<String, Object>) objValue;
379 createInputValue(mappedToscaTemplate, 1, parsedPropNames, inputName);
381 String json = gson.toJson(mappedToscaTemplate);
387 jsonObject.put(GET_INPUT, input.getName());
388 prop.setValue(jsonObject.toJSONString());
394 if(CollectionUtils.isEmpty(prop.getGetInputValues())){
395 prop.setGetInputValues(new ArrayList<>());
397 List<GetInputValueDataDefinition> getInputValues = prop.getGetInputValues();
399 GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
400 getInputValueDataDefinition.setInputId(input.getUniqueId());
401 getInputValueDataDefinition.setInputName(input.getName());
402 getInputValues.add(getInputValueDataDefinition);
405 private JSONObject createJSONValueForProperty (int i, String [] parsedPropNames, JSONObject ooj, String inputName){
408 if( i == parsedPropNames.length -1){
409 JSONObject jobProp = new JSONObject();
410 jobProp.put(GET_INPUT, inputName);
411 ooj.put(parsedPropNames[i], jobProp);
413 return createJSONValueForProperty (i, parsedPropNames, ooj, inputName);
415 JSONObject res = new JSONObject();
416 res.put(parsedPropNames[i], ooj);
418 res = createJSONValueForProperty (i, parsedPropNames, res, inputName);
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);
437 return createInputValue((Map)value, index, inputNames, inputName);
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);
446 lhm1.put(inputNames[index], jobProp);
448 return createInputValue(jobProp, index, inputNames, inputName);
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);
459 return createInputValue(jobProp, index, inputNames, inputName);
466 private class PropertiesDeclarationData {
467 private List<InputDefinition> inputsToCreate;
468 private List<PolicyDefinition> policiesToCreate;
469 private List<PROPERTYTYPE> propertiesToUpdate;
471 PropertiesDeclarationData(List<InputDefinition> inputsToCreate, List<PolicyDefinition> policiesToCreate, List<PROPERTYTYPE> propertiesToUpdate) {
472 this.inputsToCreate = inputsToCreate;
473 this.policiesToCreate = policiesToCreate;
474 this.propertiesToUpdate = propertiesToUpdate;
477 List<InputDefinition> getInputsToCreate() {
478 return inputsToCreate;
481 public List<PolicyDefinition> getPoliciesToCreate() { return policiesToCreate; }
483 List<PROPERTYTYPE> getPropertiesToUpdate() {
484 return propertiesToUpdate;
488 Either<InputDefinition, ResponseFormat> prepareValueBeforeDelete(InputDefinition inputForDelete, PropertyDataDefinition inputValue, List<String> pathOfComponentInstances) {
489 Either<InputDefinition, ResponseFormat> deleteEither = prepareValueBeforeDelete(inputForDelete, inputValue);
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()))));
500 String defaultValue = findDefaultValue.left().value();
501 inputValue.setDefaultValue(defaultValue);
502 log.debug("The returned default value in ResourceInstanceProperty is {}", defaultValue);
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());
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);
520 resetInputName(mappedToscaTemplate, inputForDelete.getName());
523 if (!mappedToscaTemplate.isEmpty()) {
524 Either result = cleanNestedMap(mappedToscaTemplate, true);
525 Map modifiedMappedToscaTemplate = mappedToscaTemplate;
526 if (result.isLeft()) {
527 modifiedMappedToscaTemplate = (Map) result.left().value();
529 log.warn("Map cleanup failed -> " + result.right().value()
530 .toString()); //continue, don't break operation
532 value = gson.toJson(modifiedMappedToscaTemplate);
534 inputValue.setValue(value);
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()))
542 op.ifPresent(getInputsValues::remove);
544 inputValue.setGetInputValues(getInputsValues);
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)) {
555 } else if (value instanceof Map) {
556 Map<String, Object> subMap = (Map<String, Object>)value;
557 resetInputName(subMap, inputName);
558 } else if (value instanceof List && ((List) value).contains(inputName) && key.equals(GET_INPUT)) {
568 private Either cleanNestedMap( Map mappedToscaTemplate , boolean deepClone ){
569 if (MapUtils.isNotEmpty( mappedToscaTemplate ) ){
571 if (!(mappedToscaTemplate instanceof HashMap))
572 return Either.right("expecting mappedToscaTemplate as HashMap ,recieved "+ mappedToscaTemplate.getClass().getSimpleName() );
574 mappedToscaTemplate = (HashMap)((HashMap) mappedToscaTemplate).clone();
576 return Either.left( (Map) cleanEmptyNestedValuesInMap( mappedToscaTemplate , LOOP_PROTECTION_LEVEL ) );
579 log.debug("mappedToscaTemplate is empty ");
580 return Either.right("mappedToscaTemplate is empty ");
584 /* Mutates the object
585 * Tail recurse -> traverse the tosca elements and remove nested empty map properties
586 * this only handles nested maps, other objects are left untouched (even a Set containing a map) since behaviour is unexpected
588 * @param toscaElement - expected map of tosca values
589 * @return mutated @param toscaElement , where empty maps are deleted , return null for empty map.
591 private Object cleanEmptyNestedValuesInMap(Object toscaElement , short loopProtectionLevel ){
592 if (loopProtectionLevel<=0 || toscaElement==null || !(toscaElement instanceof Map))
594 if ( MapUtils.isNotEmpty( (Map)toscaElement ) ) {
596 Set<Object> keysToRemove = new HashSet<>(); // use different set to avoid ConcurrentModificationException
597 for( Object key : ((Map)toscaElement).keySet() ) {
598 Object value = ((Map) toscaElement).get(key);
599 ret = cleanEmptyNestedValuesInMap(value , --loopProtectionLevel );
601 keysToRemove.add(key);
603 Collection set = ((Map) toscaElement).keySet();
604 if (CollectionUtils.isNotEmpty(set))
605 set.removeAll(keysToRemove);
607 if ( isEmptyNestedMap(toscaElement) )
615 //@returns true iff map nested maps are all empty
616 //ignores other collection objects
617 private boolean isEmptyNestedMap(Object element){
618 boolean isEmpty = true;
619 if (element != null){
620 if ( element instanceof Map ){
621 if (MapUtils.isEmpty((Map)element))
625 for( Object key : ((Map)(element)).keySet() ){
626 Object value = ((Map)(element)).get(key);
627 isEmpty &= isEmptyNestedMap( value );