1 package org.openecomp.sdc.be.components.property;
3 import static org.openecomp.sdc.common.api.Constants.GET_INPUT;
4 import static org.openecomp.sdc.common.api.Constants.GET_POLICY;
6 import com.google.gson.Gson;
8 import java.util.ArrayList;
9 import java.util.Collection;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.List;
14 import java.util.Arrays;
15 import java.util.Objects;
16 import java.util.Optional;
18 import java.util.stream.Collectors;
19 import org.apache.commons.collections.CollectionUtils;
20 import org.apache.commons.collections.MapUtils;
21 import org.apache.commons.lang.StringUtils;
22 import org.json.simple.JSONObject;
23 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
24 import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
25 import org.openecomp.sdc.be.datatypes.elements.GetPolicyValueDataDefinition;
26 import org.openecomp.sdc.be.datatypes.elements.PropertiesOwner;
27 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
28 import org.openecomp.sdc.be.impl.ComponentsUtils;
29 import org.openecomp.sdc.be.model.Component;
30 import org.openecomp.sdc.be.model.ComponentInstancePropInput;
31 import org.openecomp.sdc.be.model.IComponentInstanceConnectedElement;
32 import org.openecomp.sdc.be.model.InputDefinition;
33 import org.openecomp.sdc.be.model.PolicyDefinition;
34 import org.openecomp.sdc.be.model.PropertyDefinition;
35 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
36 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
37 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
38 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
39 import org.openecomp.sdc.common.log.wrappers.Logger;
40 import org.openecomp.sdc.exception.ResponseFormat;
41 import org.yaml.snakeyaml.Yaml;
43 public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends PropertiesOwner, PROPERTYTYPE extends PropertyDataDefinition> implements PropertyDeclarator {
45 private static final Logger log = Logger.getLogger(DefaultPropertyDeclarator.class);
46 private static final short LOOP_PROTECTION_LEVEL = 10;
47 private final Gson gson = new Gson();
48 private ComponentsUtils componentsUtils;
49 private PropertyOperation propertyOperation;
50 private static final String GET_INPUT_INDEX = "INDEX";
52 public DefaultPropertyDeclarator(ComponentsUtils componentsUtils, PropertyOperation propertyOperation) {
53 this.componentsUtils = componentsUtils;
54 this.propertyOperation = propertyOperation;
58 public Either<List<InputDefinition>, StorageOperationStatus> declarePropertiesAsInputs(Component component, String propertiesOwnerId, List<ComponentInstancePropInput> propsToDeclare) {
59 log.debug("#declarePropertiesAsInputs - declaring properties as inputs for component {} from properties owner {}", component.getUniqueId(), propertiesOwnerId);
60 return resolvePropertiesOwner(component, propertiesOwnerId)
61 .map(propertyOwner -> declarePropertiesAsInputs(component, propertyOwner, propsToDeclare))
62 .orElse(Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId)));
65 protected abstract PROPERTYTYPE createDeclaredProperty(PropertyDataDefinition prop);
67 protected abstract Either<?, StorageOperationStatus> updatePropertiesValues(Component component, String propertiesOwnerId, List<PROPERTYTYPE> properties);
69 protected abstract Optional<PROPERTYOWNER> resolvePropertiesOwner(Component component, String propertiesOwnerId);
71 protected abstract void addPropertiesListToInput(PROPERTYTYPE declaredProp, InputDefinition input);
74 public Either<List<PolicyDefinition>, StorageOperationStatus> declarePropertiesAsPolicies(Component component,
75 String propertiesOwnerId,
76 List<ComponentInstancePropInput> propsToDeclare) {
77 log.debug("#declarePropertiesAsPolicies - declaring properties as policies for component {} from properties owner {}", component.getUniqueId(), propertiesOwnerId);
78 return resolvePropertiesOwner(component, propertiesOwnerId)
79 .map(propertyOwner -> declarePropertiesAsPolicies(component, propertyOwner, propsToDeclare))
80 .orElse(Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId)));
84 public Either<InputDefinition, StorageOperationStatus> declarePropertiesAsListInput(Component component, String propertiesOwnerId, List<ComponentInstancePropInput> propsToDeclare, InputDefinition input) {
85 log.debug("#declarePropertiesAsListInput - declaring properties as inputs for component {} from properties owner {}", component.getUniqueId(), propertiesOwnerId);
86 Optional<PROPERTYOWNER> propertyOwner = resolvePropertiesOwner(component, propertiesOwnerId);
87 if (propertyOwner.isPresent()) {
88 return declarePropertiesAsListInput(component, propertyOwner.get(), propsToDeclare, input);
90 return Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId));
94 public StorageOperationStatus unDeclarePropertiesAsPolicies(Component component, PolicyDefinition policy) {
95 return StorageOperationStatus.OK;
98 private Either<List<PolicyDefinition>, StorageOperationStatus> declarePropertiesAsPolicies(Component component, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare) {
99 PropertiesDeclarationData policyProperties = createPoliciesAndOverridePropertiesValues(propertiesOwner.getUniqueId(), propertiesOwner, propsToDeclare);
100 return updatePropertiesValues(component, propertiesOwner.getUniqueId(), policyProperties.getPropertiesToUpdate())
102 .map(updatePropsRes -> policyProperties.getPoliciesToCreate());
105 private StorageOperationStatus onPropertiesOwnerNotFound(String componentId, String propertiesOwnerId) {
106 log.debug("#declarePropertiesAsInputs - properties owner {} was not found on component {}", propertiesOwnerId, componentId);
107 return StorageOperationStatus.NOT_FOUND;
110 private Either<List<InputDefinition>, StorageOperationStatus> declarePropertiesAsInputs(Component component, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare) {
111 PropertiesDeclarationData inputsProperties = createInputsAndOverridePropertiesValues(component.getUniqueId(), propertiesOwner, propsToDeclare);
112 return updatePropertiesValues(component, propertiesOwner.getUniqueId(), inputsProperties.getPropertiesToUpdate())
114 .map(updatePropsRes -> inputsProperties.getInputsToCreate());
116 private PropertiesDeclarationData createPoliciesAndOverridePropertiesValues(String componentId, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare) {
117 List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
118 List<PolicyDefinition> policies = new ArrayList<>();
119 propsToDeclare.forEach(property -> policies.add(declarePropertyPolicy(componentId, declaredProperties, property)));
120 return new PropertiesDeclarationData(null, policies, declaredProperties);
123 private PolicyDefinition declarePropertyPolicy(String componentId, List<PROPERTYTYPE> declaredProperties,
124 ComponentInstancePropInput propInput) {
125 PropertyDataDefinition prop = resolveProperty(declaredProperties, propInput);
126 propInput.setOwnerId(null);
127 propInput.setParentUniqueId(null);
129 PolicyDefinition policyDefinition = new PolicyDefinition(prop);
130 policyDefinition.setUniqueId(UniqueIdBuilder.buildPolicyUniqueId(componentId, prop.getName()));
131 policyDefinition.setInputPath(prop.getName());
132 policyDefinition.setInstanceUniqueId(componentId);
134 changePropertyValueToGetPolicy(prop, policyDefinition);
135 PROPERTYTYPE declaredProperty = createDeclaredProperty(prop);
138 if(!declaredProperties.contains(declaredProperty)){
139 declaredProperties.add(declaredProperty);
142 return policyDefinition;
145 private void changePropertyValueToGetPolicy(PropertyDataDefinition prop, PolicyDefinition policyDefinition) {
146 JSONObject jsonObject = new JSONObject();
148 String origValue = Objects.isNull(prop.getValue()) ? prop.getDefaultValue() : prop.getValue();
149 jsonObject.put(GET_POLICY, null);
150 prop.setValue(jsonObject.toJSONString());
151 policyDefinition.setValue(jsonObject.toJSONString());
153 if(CollectionUtils.isEmpty(prop.getGetPolicyValues())){
154 prop.setGetPolicyValues(new ArrayList<>());
156 List<GetPolicyValueDataDefinition> getPolicyValues = prop.getGetPolicyValues();
158 GetPolicyValueDataDefinition getPolicyValueDataDefinition = new GetPolicyValueDataDefinition();
159 getPolicyValueDataDefinition.setPolicyId(policyDefinition.getUniqueId());
160 getPolicyValueDataDefinition.setPropertyName(prop.getName());
162 getPolicyValueDataDefinition.setOrigPropertyValue(origValue);
164 getPolicyValues.add(getPolicyValueDataDefinition);
166 policyDefinition.setGetPolicyValues(getPolicyValues);
171 private Either<InputDefinition, StorageOperationStatus> declarePropertiesAsListInput(Component component, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare, InputDefinition input) {
172 List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
173 for (ComponentInstancePropInput propInput : propsToDeclare) {
174 if (StringUtils.isNotEmpty(propInput.getPropertiesName()) && propInput.getInput() != null) {
175 // sub-property in complex type is checked on UI. currently not supported.
176 log.debug("skip propInput (propertiesName={}) currently not supported.", propInput.getPropertiesName());
179 PROPERTYTYPE declaredProperty = createDeclaredProperty(propInput);
181 JSONObject jsonObject = new JSONObject();
182 jsonObject.put(GET_INPUT, Arrays.asList(input.getName(), GET_INPUT_INDEX, propInput.getName()));
183 declaredProperty.setValue(jsonObject.toJSONString());
185 GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
186 getInputValueDataDefinition.setInputId(input.getUniqueId());
187 getInputValueDataDefinition.setInputName(input.getName());
188 List<GetInputValueDataDefinition> getInputValues = declaredProperty.getGetInputValues();
189 if (getInputValues == null) {
190 getInputValues = new ArrayList<>();
191 declaredProperty.setGetInputValues(getInputValues);
193 getInputValues.add(getInputValueDataDefinition);
195 if (!declaredProperties.contains(declaredProperty)) {
196 // Add property to the list if not contain in declareProperties.
197 declaredProperties.add(declaredProperty);
200 return updatePropertiesValues(component, propertiesOwner.getUniqueId(), declaredProperties)
201 .left().map(x -> input);
204 private PropertiesDeclarationData createInputsAndOverridePropertiesValues(String componentId, PROPERTYOWNER propertiesOwner, List<ComponentInstancePropInput> propsToDeclare) {
205 List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
206 List<InputDefinition> createdInputs = propsToDeclare.stream()
207 .map(propInput -> declarePropertyInput(componentId, propertiesOwner, declaredProperties, propInput))
208 .collect(Collectors.toList());
209 return new PropertiesDeclarationData(createdInputs, null, declaredProperties);
212 private InputDefinition declarePropertyInput(String componentId, PROPERTYOWNER propertiesOwner, List<PROPERTYTYPE> declaredProperties, ComponentInstancePropInput propInput) {
213 PropertyDataDefinition prop = resolveProperty(declaredProperties, propInput);
214 InputDefinition inputDefinition = createInput(componentId, propertiesOwner, propInput, prop);
215 PROPERTYTYPE declaredProperty = createDeclaredProperty(prop);
216 if(!declaredProperties.contains(declaredProperty)){
217 declaredProperties.add(declaredProperty);
219 addPropertiesListToInput(declaredProperty, inputDefinition);
220 return inputDefinition;
223 private InputDefinition createInput(String componentId, PROPERTYOWNER propertiesOwner,
224 ComponentInstancePropInput propInput, PropertyDataDefinition prop) {
225 String generatedInputPrefix = propertiesOwner.getNormalizedName();
226 if (propertiesOwner.getUniqueId().equals(propInput.getParentUniqueId())) {
227 //Creating input from property create on self using add property..Do not add the prefix
228 generatedInputPrefix = null;
230 String generatedInputName = generateInputName(generatedInputPrefix, propInput);
231 log.debug("createInput: propOwner.uniqueId={}, propInput.parentUniqueId={}", propertiesOwner.getUniqueId(), propInput.getParentUniqueId());
232 return createInputFromProperty(componentId, propertiesOwner, generatedInputName, propInput, prop);
235 private String generateInputName(String inputName, ComponentInstancePropInput propInput) {
236 String declaredInputName;
237 String[] parsedPropNames = propInput.getParsedPropNames();
239 if(parsedPropNames != null){
240 declaredInputName = handleInputName(inputName, parsedPropNames);
242 String[] propName = {propInput.getName()};
243 declaredInputName = handleInputName(inputName, propName);
246 return declaredInputName;
249 private String handleInputName(String inputName, String[] parsedPropNames) {
250 StringBuilder prefix = new StringBuilder();
253 if(Objects.isNull(inputName)) {
254 prefix.append(parsedPropNames[0]);
257 prefix.append(inputName);
261 while(startingIndex < parsedPropNames.length){
263 prefix.append(parsedPropNames[startingIndex]);
267 return prefix.toString();
270 private PropertyDataDefinition resolveProperty(List<PROPERTYTYPE> propertiesToCreate, ComponentInstancePropInput propInput) {
271 Optional<PROPERTYTYPE> resolvedProperty = propertiesToCreate.stream()
272 .filter(p -> p.getName().equals(propInput.getName()))
274 return resolvedProperty.isPresent() ? resolvedProperty.get() : propInput;
277 InputDefinition createInputFromProperty(String componentId, PROPERTYOWNER propertiesOwner, String inputName, ComponentInstancePropInput propInput, PropertyDataDefinition prop) {
278 String propertiesName = propInput.getPropertiesName() ;
279 PropertyDefinition selectedProp = propInput.getInput();
280 String[] parsedPropNames = propInput.getParsedPropNames();
281 InputDefinition input;
282 boolean complexProperty = false;
283 if(propertiesName != null && !propertiesName.isEmpty() && selectedProp != null){
284 complexProperty = true;
285 input = new InputDefinition(selectedProp);
286 input.setDefaultValue(selectedProp.getValue());
288 input = new InputDefinition(prop);
289 input.setDefaultValue(prop.getValue());
291 input.setName(inputName);
292 input.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(componentId, input.getName()));
293 input.setInputPath(propertiesName);
294 input.setInstanceUniqueId(propertiesOwner.getUniqueId());
295 input.setPropertyId(propInput.getUniqueId());
296 if (Objects.isNull(input.getSubPropertyInputPath())
297 || (Objects.nonNull(propertiesName)
298 && input.getSubPropertyInputPath().substring(input.getSubPropertyInputPath().lastIndexOf('#'))
299 .equals(propertiesName.substring(propertiesName.lastIndexOf('#'))))) {
300 input.setParentPropertyType(propInput.getType());
301 input.setSubPropertyInputPath(propertiesName);
304 changePropertyValueToGetInputValue(inputName, parsedPropNames, input, prop, complexProperty);
306 if(prop instanceof IComponentInstanceConnectedElement) {
307 ((IComponentInstanceConnectedElement) prop)
308 .setComponentInstanceId(propertiesOwner.getUniqueId());
309 ((IComponentInstanceConnectedElement) prop)
310 .setComponentInstanceName(propertiesOwner.getName());
315 private void changePropertyValueToGetInputValue(String inputName, String[] parsedPropNames, InputDefinition input, PropertyDataDefinition prop, boolean complexProperty) {
316 JSONObject jsonObject = new JSONObject();
317 String value = prop.getValue();
318 if(value == null || value.isEmpty()){
321 jsonObject = createJSONValueForProperty(parsedPropNames.length -1, parsedPropNames, jsonObject, inputName);
322 prop.setValue(jsonObject.toJSONString());
326 jsonObject.put(GET_INPUT, input.getName());
327 prop.setValue(jsonObject.toJSONString());
333 Object objValue = new Yaml().load(value);
334 if( objValue instanceof Map || objValue instanceof List){
335 if(!complexProperty){
336 jsonObject.put(GET_INPUT, input.getName());
337 prop.setValue(jsonObject.toJSONString());
341 Map<String, Object> mappedToscaTemplate = (Map<String, Object>) objValue;
342 createInputValue(mappedToscaTemplate, 1, parsedPropNames, inputName);
344 String json = gson.toJson(mappedToscaTemplate);
350 jsonObject.put(GET_INPUT, input.getName());
351 prop.setValue(jsonObject.toJSONString());
357 if(CollectionUtils.isEmpty(prop.getGetInputValues())){
358 prop.setGetInputValues(new ArrayList<>());
360 List<GetInputValueDataDefinition> getInputValues = prop.getGetInputValues();
362 GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
363 getInputValueDataDefinition.setInputId(input.getUniqueId());
364 getInputValueDataDefinition.setInputName(input.getName());
365 getInputValues.add(getInputValueDataDefinition);
368 private JSONObject createJSONValueForProperty (int i, String [] parsedPropNames, JSONObject ooj, String inputName){
371 if( i == parsedPropNames.length -1){
372 JSONObject jobProp = new JSONObject();
373 jobProp.put(GET_INPUT, inputName);
374 ooj.put(parsedPropNames[i], jobProp);
376 return createJSONValueForProperty (i, parsedPropNames, ooj, inputName);
378 JSONObject res = new JSONObject();
379 res.put(parsedPropNames[i], ooj);
381 res = createJSONValueForProperty (i, parsedPropNames, res, inputName);
389 private Map<String, Object> createInputValue(Map<String, Object> lhm1, int index, String[] inputNames, String inputName){
390 while(index < inputNames.length){
391 if(lhm1.containsKey(inputNames[index])){
392 Object value = lhm1.get(inputNames[index]);
393 if (value instanceof Map){
394 if(index == inputNames.length -1){
395 ((Map) value).put(GET_INPUT, inputName);
400 return createInputValue((Map)value, index, inputNames, inputName);
403 Map<String, Object> jobProp = new HashMap<>();
404 if(index == inputNames.length -1){
405 jobProp.put(GET_INPUT, inputName);
406 lhm1.put(inputNames[index], jobProp);
409 lhm1.put(inputNames[index], jobProp);
411 return createInputValue(jobProp, index, inputNames, inputName);
415 Map<String, Object> jobProp = new HashMap<>();
416 lhm1.put(inputNames[index], jobProp);
417 if(index == inputNames.length -1){
418 jobProp.put(GET_INPUT, inputName);
422 return createInputValue(jobProp, index, inputNames, inputName);
429 private class PropertiesDeclarationData {
430 private List<InputDefinition> inputsToCreate;
431 private List<PolicyDefinition> policiesToCreate;
432 private List<PROPERTYTYPE> propertiesToUpdate;
434 PropertiesDeclarationData(List<InputDefinition> inputsToCreate, List<PolicyDefinition> policiesToCreate, List<PROPERTYTYPE> propertiesToUpdate) {
435 this.inputsToCreate = inputsToCreate;
436 this.policiesToCreate = policiesToCreate;
437 this.propertiesToUpdate = propertiesToUpdate;
440 List<InputDefinition> getInputsToCreate() {
441 return inputsToCreate;
444 public List<PolicyDefinition> getPoliciesToCreate() { return policiesToCreate; }
446 List<PROPERTYTYPE> getPropertiesToUpdate() {
447 return propertiesToUpdate;
451 Either<InputDefinition, ResponseFormat> prepareValueBeforeDelete(InputDefinition inputForDelete, PropertyDataDefinition inputValue, List<String> pathOfComponentInstances) {
452 Either<InputDefinition, ResponseFormat> deleteEither = Either.left(inputForDelete);
453 String value = inputValue.getValue();
454 Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(value);
456 resetInputName(mappedToscaTemplate, inputForDelete.getName());
459 if(!mappedToscaTemplate.isEmpty()){
460 Either result = cleanNestedMap(mappedToscaTemplate , true);
461 Map modifiedMappedToscaTemplate = mappedToscaTemplate;
463 modifiedMappedToscaTemplate = (Map)result.left().value();
465 log.warn("Map cleanup failed -> " +result.right().value().toString()); //continue, don't break operation
466 value = gson.toJson(modifiedMappedToscaTemplate);
468 inputValue.setValue(value);
471 List<GetInputValueDataDefinition> getInputsValues = inputValue.getGetInputValues();
472 if(getInputsValues != null && !getInputsValues.isEmpty()){
473 Optional<GetInputValueDataDefinition> op = getInputsValues.stream().filter(gi -> gi.getInputId().equals(inputForDelete.getUniqueId())).findAny();
475 getInputsValues.remove(op.get());
478 inputValue.setGetInputValues(getInputsValues);
480 Either<String, TitanOperationStatus> findDefaultValue = propertyOperation.findDefaultValueFromSecondPosition(pathOfComponentInstances, inputValue.getUniqueId(), inputValue.getDefaultValue());
481 if (findDefaultValue.isRight()) {
482 deleteEither = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(findDefaultValue.right().value()))));
486 String defaultValue = findDefaultValue.left().value();
487 inputValue.setDefaultValue(defaultValue);
488 log.debug("The returned default value in ResourceInstanceProperty is {}", defaultValue);
492 private void resetInputName(Map<String, Object> lhm1, String inputName){
493 for (Map.Entry<String, Object> entry : lhm1.entrySet()) {
494 String key = entry.getKey();
495 Object value = entry.getValue();
496 if (value instanceof String && ((String) value).equalsIgnoreCase(inputName) && key.equals(GET_INPUT)) {
499 } else if (value instanceof Map) {
500 Map<String, Object> subMap = (Map<String, Object>)value;
501 resetInputName(subMap, inputName);
502 } else if (value instanceof List && ((List) value).contains(inputName) && key.equals(GET_INPUT)) {
512 private Either cleanNestedMap( Map mappedToscaTemplate , boolean deepClone ){
513 if (MapUtils.isNotEmpty( mappedToscaTemplate ) ){
515 if (!(mappedToscaTemplate instanceof HashMap))
516 return Either.right("expecting mappedToscaTemplate as HashMap ,recieved "+ mappedToscaTemplate.getClass().getSimpleName() );
518 mappedToscaTemplate = (HashMap)((HashMap) mappedToscaTemplate).clone();
520 return Either.left( (Map) cleanEmptyNestedValuesInMap( mappedToscaTemplate , LOOP_PROTECTION_LEVEL ) );
523 log.debug("mappedToscaTemplate is empty ");
524 return Either.right("mappedToscaTemplate is empty ");
528 /* Mutates the object
529 * Tail recurse -> traverse the tosca elements and remove nested empty map properties
530 * this only handles nested maps, other objects are left untouched (even a Set containing a map) since behaviour is unexpected
532 * @param toscaElement - expected map of tosca values
533 * @return mutated @param toscaElement , where empty maps are deleted , return null for empty map.
535 private Object cleanEmptyNestedValuesInMap(Object toscaElement , short loopProtectionLevel ){
536 if (loopProtectionLevel<=0 || toscaElement==null || !(toscaElement instanceof Map))
538 if ( MapUtils.isNotEmpty( (Map)toscaElement ) ) {
540 Set<Object> keysToRemove = new HashSet<>(); // use different set to avoid ConcurrentModificationException
541 for( Object key : ((Map)toscaElement).keySet() ) {
542 Object value = ((Map) toscaElement).get(key);
543 ret = cleanEmptyNestedValuesInMap(value , --loopProtectionLevel );
545 keysToRemove.add(key);
547 Collection set = ((Map) toscaElement).keySet();
548 if (CollectionUtils.isNotEmpty(set))
549 set.removeAll(keysToRemove);
551 if ( isEmptyNestedMap(toscaElement) )
559 //@returns true iff map nested maps are all empty
560 //ignores other collection objects
561 private boolean isEmptyNestedMap(Object element){
562 boolean isEmpty = true;
563 if (element != null){
564 if ( element instanceof Map ){
565 if (MapUtils.isEmpty((Map)element))
569 for( Object key : ((Map)(element)).keySet() ){
570 Object value = ((Map)(element)).get(key);
571 isEmpty &= isEmptyNestedMap( value );