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=========================================================
20 package org.openecomp.sdc.be.components.property;
22 import static org.openecomp.sdc.common.api.Constants.GET_INPUT;
23 import static org.openecomp.sdc.common.api.Constants.GET_POLICY;
25 import com.google.gson.Gson;
26 import fj.data.Either;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
34 import java.util.Objects;
35 import java.util.Optional;
37 import java.util.stream.Collectors;
38 import org.apache.commons.collections.CollectionUtils;
39 import org.apache.commons.collections.MapUtils;
40 import org.apache.commons.lang3.StringUtils;
41 import org.json.simple.JSONObject;
42 import org.openecomp.sdc.be.components.utils.PropertiesUtils;
43 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
44 import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition;
45 import org.openecomp.sdc.be.datatypes.elements.GetPolicyValueDataDefinition;
46 import org.openecomp.sdc.be.datatypes.elements.PropertiesOwner;
47 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
48 import org.openecomp.sdc.be.impl.ComponentsUtils;
49 import org.openecomp.sdc.be.model.CapabilityDefinition;
50 import org.openecomp.sdc.be.model.Component;
51 import org.openecomp.sdc.be.model.ComponentInstancePropInput;
52 import org.openecomp.sdc.be.model.IComponentInstanceConnectedElement;
53 import org.openecomp.sdc.be.model.InputDefinition;
54 import org.openecomp.sdc.be.model.PolicyDefinition;
55 import org.openecomp.sdc.be.model.PropertyDefinition;
56 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
57 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
58 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
59 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
60 import org.openecomp.sdc.common.log.wrappers.Logger;
61 import org.openecomp.sdc.exception.ResponseFormat;
62 import org.yaml.snakeyaml.Yaml;
64 public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends PropertiesOwner, PROPERTYTYPE extends PropertyDataDefinition> implements
67 private static final Logger log = Logger.getLogger(DefaultPropertyDeclarator.class);
68 private static final short LOOP_PROTECTION_LEVEL = 10;
69 private static final String UNDERSCORE = "_";
70 private static final String GET_INPUT_INDEX = "INDEX";
71 private final Gson gson = new Gson();
72 private ComponentsUtils componentsUtils;
73 private PropertyOperation propertyOperation;
75 protected DefaultPropertyDeclarator(ComponentsUtils componentsUtils, PropertyOperation propertyOperation) {
76 this.componentsUtils = componentsUtils;
77 this.propertyOperation = propertyOperation;
81 public Either<List<InputDefinition>, StorageOperationStatus> declarePropertiesAsInputs(Component component, String propertiesOwnerId,
82 List<ComponentInstancePropInput> propsToDeclare) {
83 log.debug("#declarePropertiesAsInputs - declaring properties as inputs for component {} from properties owner {}", component.getUniqueId(),
85 return resolvePropertiesOwner(component, propertiesOwnerId)
86 .map(propertyOwner -> declarePropertiesAsInputs(component, propertyOwner, propsToDeclare))
87 .orElse(Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId)));
90 protected abstract PROPERTYTYPE createDeclaredProperty(PropertyDataDefinition prop);
92 protected abstract Either<?, StorageOperationStatus> updatePropertiesValues(Component component, String propertiesOwnerId,
93 List<PROPERTYTYPE> properties);
95 protected abstract Optional<PROPERTYOWNER> resolvePropertiesOwner(Component component, String propertiesOwnerId);
97 protected abstract void addPropertiesListToInput(PROPERTYTYPE declaredProp, InputDefinition input);
100 public Either<List<PolicyDefinition>, StorageOperationStatus> declarePropertiesAsPolicies(Component component, String propertiesOwnerId,
101 List<ComponentInstancePropInput> propsToDeclare) {
102 log.debug("#declarePropertiesAsPolicies - declaring properties as policies for component {} from properties owner {}",
103 component.getUniqueId(), propertiesOwnerId);
104 return resolvePropertiesOwner(component, propertiesOwnerId)
105 .map(propertyOwner -> declarePropertiesAsPolicies(component, propertyOwner, propsToDeclare))
106 .orElse(Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId)));
110 public Either<InputDefinition, StorageOperationStatus> declarePropertiesAsListInput(Component component, String propertiesOwnerId,
111 List<ComponentInstancePropInput> propsToDeclare,
112 InputDefinition input) {
113 log.debug("#declarePropertiesAsListInput - declaring properties as inputs for component {} from properties owner {}", component.getUniqueId(),
115 Optional<PROPERTYOWNER> propertyOwner = resolvePropertiesOwner(component, propertiesOwnerId);
116 if (propertyOwner.isPresent()) {
117 return declarePropertiesAsListInput(component, propertyOwner.get(), propsToDeclare, input);
119 return Either.right(onPropertiesOwnerNotFound(component.getUniqueId(), propertiesOwnerId));
123 public StorageOperationStatus unDeclarePropertiesAsPolicies(Component component, PolicyDefinition policy) {
124 return StorageOperationStatus.OK;
127 private Either<List<PolicyDefinition>, StorageOperationStatus> declarePropertiesAsPolicies(Component component, PROPERTYOWNER propertiesOwner,
128 List<ComponentInstancePropInput> propsToDeclare) {
129 PropertiesDeclarationData policyProperties = createPoliciesAndOverridePropertiesValues(propertiesOwner.getUniqueId(), propertiesOwner,
131 return updatePropertiesValues(component, propertiesOwner.getUniqueId(), policyProperties.getPropertiesToUpdate()).left()
132 .map(updatePropsRes -> policyProperties.getPoliciesToCreate());
135 private StorageOperationStatus onPropertiesOwnerNotFound(String componentId, String propertiesOwnerId) {
136 log.debug("#declarePropertiesAsInputs - properties owner {} was not found on component {}", propertiesOwnerId, componentId);
137 return StorageOperationStatus.NOT_FOUND;
140 private Either<List<InputDefinition>, StorageOperationStatus> declarePropertiesAsInputs(Component component, PROPERTYOWNER propertiesOwner,
141 List<ComponentInstancePropInput> propsToDeclare) {
142 PropertiesDeclarationData inputsProperties = createInputsAndOverridePropertiesValues(component, propertiesOwner, propsToDeclare);
143 return updatePropertiesValues(component, propertiesOwner.getUniqueId(), inputsProperties.getPropertiesToUpdate()).left()
144 .map(updatePropsRes -> inputsProperties.getInputsToCreate());
147 private PropertiesDeclarationData createPoliciesAndOverridePropertiesValues(String componentId, PROPERTYOWNER propertiesOwner,
148 List<ComponentInstancePropInput> propsToDeclare) {
149 List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
150 List<PolicyDefinition> policies = new ArrayList<>();
151 propsToDeclare.forEach(property -> policies.add(declarePropertyPolicy(componentId, declaredProperties, property)));
152 return new PropertiesDeclarationData(null, policies, declaredProperties);
155 private PolicyDefinition declarePropertyPolicy(String componentId, List<PROPERTYTYPE> declaredProperties, ComponentInstancePropInput propInput) {
156 PropertyDataDefinition prop = resolveProperty(declaredProperties, propInput);
157 propInput.setOwnerId(null);
158 propInput.setParentUniqueId(null);
159 PolicyDefinition policyDefinition = new PolicyDefinition(prop);
160 policyDefinition.setUniqueId(UniqueIdBuilder.buildPolicyUniqueId(componentId, prop.getName()));
161 policyDefinition.setInputPath(prop.getName());
162 policyDefinition.setInstanceUniqueId(componentId);
163 policyDefinition.setPropertyId(prop.getUniqueId());
164 changePropertyValueToGetPolicy(prop, policyDefinition);
165 PROPERTYTYPE declaredProperty = createDeclaredProperty(prop);
166 if (!declaredProperties.contains(declaredProperty)) {
167 declaredProperties.add(declaredProperty);
169 return policyDefinition;
172 private void changePropertyValueToGetPolicy(PropertyDataDefinition prop, PolicyDefinition policyDefinition) {
173 JSONObject jsonObject = new JSONObject();
174 String origValue = Objects.isNull(prop.getValue()) ? prop.getDefaultValue() : prop.getValue();
175 jsonObject.put(GET_POLICY, null);
176 prop.setValue(jsonObject.toJSONString());
177 policyDefinition.setValue(jsonObject.toJSONString());
178 if (CollectionUtils.isEmpty(prop.getGetPolicyValues())) {
179 prop.setGetPolicyValues(new ArrayList<>());
181 List<GetPolicyValueDataDefinition> getPolicyValues = prop.getGetPolicyValues();
182 GetPolicyValueDataDefinition getPolicyValueDataDefinition = new GetPolicyValueDataDefinition();
183 getPolicyValueDataDefinition.setPolicyId(policyDefinition.getUniqueId());
184 getPolicyValueDataDefinition.setPropertyName(prop.getName());
185 getPolicyValueDataDefinition.setOrigPropertyValue(origValue);
186 getPolicyValues.add(getPolicyValueDataDefinition);
187 policyDefinition.setGetPolicyValues(getPolicyValues);
190 private Either<InputDefinition, StorageOperationStatus> declarePropertiesAsListInput(Component component, PROPERTYOWNER propertiesOwner,
191 List<ComponentInstancePropInput> propsToDeclare,
192 InputDefinition input) {
193 List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
194 for (ComponentInstancePropInput propInput : propsToDeclare) {
195 if (StringUtils.isNotEmpty(propInput.getPropertiesName()) && propInput.getInput() != null) {
196 // sub-property in complex type is checked on UI. currently not supported.
197 log.debug("skip propInput (propertiesName={}) currently not supported.", propInput.getPropertiesName());
200 PROPERTYTYPE declaredProperty = createDeclaredProperty(propInput);
201 JSONObject jsonObject = new JSONObject();
202 jsonObject.put(GET_INPUT, Arrays.asList(input.getName(), GET_INPUT_INDEX, propInput.getName()));
203 declaredProperty.setValue(jsonObject.toJSONString());
204 GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
205 getInputValueDataDefinition.setInputId(input.getUniqueId());
206 getInputValueDataDefinition.setInputName(input.getName());
207 List<GetInputValueDataDefinition> getInputValues = declaredProperty.getGetInputValues();
208 if (getInputValues == null) {
209 getInputValues = new ArrayList<>();
210 declaredProperty.setGetInputValues(getInputValues);
212 getInputValues.add(getInputValueDataDefinition);
213 if (!declaredProperties.contains(declaredProperty)) {
214 // Add property to the list if not contain in declareProperties.
215 declaredProperties.add(declaredProperty);
218 return updatePropertiesValues(component, propertiesOwner.getUniqueId(), declaredProperties).left().map(x -> input);
221 private PropertiesDeclarationData createInputsAndOverridePropertiesValues(Component component, PROPERTYOWNER propertiesOwner,
222 List<ComponentInstancePropInput> propsToDeclare) {
223 List<PROPERTYTYPE> declaredProperties = new ArrayList<>();
224 List<InputDefinition> createdInputs = propsToDeclare.stream()
225 .map(propInput -> declarePropertyInput(component, propertiesOwner, declaredProperties, propInput)).collect(Collectors.toList());
226 return new PropertiesDeclarationData(createdInputs, null, declaredProperties);
229 private InputDefinition declarePropertyInput(Component component, PROPERTYOWNER propertiesOwner, List<PROPERTYTYPE> declaredProperties,
230 ComponentInstancePropInput propInput) {
231 PropertyDataDefinition prop = resolveProperty(declaredProperties, propInput);
232 InputDefinition inputDefinition = createInput(component, propertiesOwner, propInput, prop);
233 PROPERTYTYPE declaredProperty = createDeclaredProperty(prop);
234 if (!declaredProperties.contains(declaredProperty)) {
235 declaredProperties.add(declaredProperty);
237 addPropertiesListToInput(declaredProperty, inputDefinition);
238 return inputDefinition;
241 private InputDefinition createInput(Component component, PROPERTYOWNER propertiesOwner, ComponentInstancePropInput propInput,
242 PropertyDataDefinition prop) {
243 String generatedInputPrefix = propertiesOwner.getNormalizedName();
244 if (component.getUniqueId().equals(propInput.getParentUniqueId())) {
245 //Creating input from property create on self using add property..Do not add the prefix
246 generatedInputPrefix = null;
248 Optional<CapabilityDefinition> propertyCapability = PropertiesUtils
249 .getPropertyCapabilityOfChildInstance(propInput.getParentUniqueId(), component.getCapabilities());
250 if (propertyCapability.isPresent()) {
251 String capName = propertyCapability.get().getName();
252 if (capName.contains(".")) {
253 capName = capName.replaceAll("\\.", UNDERSCORE);
255 generatedInputPrefix =
256 generatedInputPrefix == null || generatedInputPrefix.isEmpty() ? capName : generatedInputPrefix + UNDERSCORE + capName;
258 String generatedInputName = null;
259 if (StringUtils.isNotEmpty(propInput.getInputName())) {
260 generatedInputName = propInput.getInputName();
262 generatedInputName = generateInputName(generatedInputPrefix, propInput);
264 log.debug("createInput: propOwner.uniqueId={}, propInput.parentUniqueId={}", propertiesOwner.getUniqueId(), propInput.getParentUniqueId());
265 return createInputFromProperty(component.getUniqueId(), propertiesOwner, generatedInputName, propInput, prop);
268 private String generateInputName(String inputName, ComponentInstancePropInput propInput) {
269 String declaredInputName;
270 String[] parsedPropNames = propInput.getParsedPropNames();
271 if (parsedPropNames != null) {
272 declaredInputName = handleInputName(inputName, parsedPropNames);
274 String[] propName = {propInput.getName()};
275 declaredInputName = handleInputName(inputName, propName);
277 return validateDeclaredInputName(declaredInputName);
280 private String validateDeclaredInputName(String inputName) {
281 return inputName.replace("::", "_");
284 private String handleInputName(String inputName, String[] parsedPropNames) {
285 StringBuilder prefix = new StringBuilder();
287 if (Objects.isNull(inputName)) {
288 prefix.append(parsedPropNames[0]);
291 prefix.append(inputName);
294 while (startingIndex < parsedPropNames.length) {
295 prefix.append(UNDERSCORE);
296 prefix.append(parsedPropNames[startingIndex]);
299 return prefix.toString();
302 private PropertyDataDefinition resolveProperty(List<PROPERTYTYPE> propertiesToCreate, ComponentInstancePropInput propInput) {
303 Optional<PROPERTYTYPE> resolvedProperty = propertiesToCreate.stream().filter(p -> p.getName().equals(propInput.getName())).findFirst();
304 return resolvedProperty.isPresent() ? resolvedProperty.get() : propInput;
307 InputDefinition createInputFromProperty(String componentId, PROPERTYOWNER propertiesOwner, String inputName, ComponentInstancePropInput propInput,
308 PropertyDataDefinition prop) {
309 String propertiesName = propInput.getPropertiesName();
310 PropertyDefinition selectedProp = propInput.getInput();
311 String[] parsedPropNames = propInput.getParsedPropNames();
312 InputDefinition input;
313 boolean complexProperty = false;
315 if (propertiesName != null && !propertiesName.isEmpty() && selectedProp != null) {
316 complexProperty = true;
317 input = new InputDefinition(selectedProp);
318 input.setDefaultValue(selectedProp.getValue());
320 input = new InputDefinition(prop);
321 input.setDefaultValue(prop.getValue());
324 input.setName(inputName);
325 input.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(componentId, input.getName()));
326 input.setInputPath(propertiesName);
327 input.setInstanceUniqueId(propertiesOwner.getUniqueId());
328 input.setPropertyId(propInput.getUniqueId());
330 if (Objects.isNull(input.getSubPropertyInputPath()) || (propertiesName != null && input.getSubPropertyInputPath()
331 .substring(input.getSubPropertyInputPath().lastIndexOf('#')).equals(propertiesName.substring(propertiesName.lastIndexOf('#'))))) {
332 input.setParentPropertyType(propInput.getType());
333 input.setSubPropertyInputPath(propertiesName);
336 changePropertyValueToGetInputValue(inputName, parsedPropNames, input, prop, complexProperty);
338 if (prop instanceof IComponentInstanceConnectedElement) {
339 ((IComponentInstanceConnectedElement) prop).setComponentInstanceId(propertiesOwner.getUniqueId());
340 ((IComponentInstanceConnectedElement) prop).setComponentInstanceName(propertiesOwner.getName());
346 private void changePropertyValueToGetInputValue(String inputName, String[] parsedPropNames, InputDefinition input, PropertyDataDefinition prop,
347 boolean complexProperty) {
348 JSONObject jsonObject = new JSONObject();
349 String value = prop.getValue();
350 if (value == null || value.isEmpty()) {
351 if (complexProperty) {
352 jsonObject = createJSONValueForProperty(parsedPropNames.length - 1, parsedPropNames, jsonObject, inputName);
353 prop.setValue(jsonObject.toJSONString());
355 jsonObject.put(GET_INPUT, input.getName());
356 prop.setValue(jsonObject.toJSONString());
359 Object objValue = new Yaml().load(value);
360 if (objValue instanceof Map || objValue instanceof List) {
361 if (!complexProperty) {
362 jsonObject.put(GET_INPUT, input.getName());
363 prop.setValue(jsonObject.toJSONString());
365 Map<String, Object> mappedToscaTemplate = (Map<String, Object>) objValue;
366 createInputValue(mappedToscaTemplate, 1, parsedPropNames, inputName);
367 String json = gson.toJson(mappedToscaTemplate);
371 jsonObject.put(GET_INPUT, input.getName());
372 prop.setValue(jsonObject.toJSONString());
375 if (CollectionUtils.isEmpty(prop.getGetInputValues())) {
376 prop.setGetInputValues(new ArrayList<>());
378 List<GetInputValueDataDefinition> getInputValues = prop.getGetInputValues();
379 GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
380 getInputValueDataDefinition.setInputId(input.getUniqueId());
381 getInputValueDataDefinition.setInputName(input.getName());
382 getInputValues.add(getInputValueDataDefinition);
385 private JSONObject createJSONValueForProperty(int i, String[] parsedPropNames, JSONObject ooj, String inputName) {
387 if (i == parsedPropNames.length - 1) {
388 JSONObject jobProp = new JSONObject();
389 jobProp.put(GET_INPUT, inputName);
390 ooj.put(parsedPropNames[i], jobProp);
392 return createJSONValueForProperty(i, parsedPropNames, ooj, inputName);
394 JSONObject res = new JSONObject();
395 res.put(parsedPropNames[i], ooj);
397 res = createJSONValueForProperty(i, parsedPropNames, res, inputName);
404 private Map<String, Object> createInputValue(Map<String, Object> lhm1, int index, String[] inputNames, String inputName) {
405 while (index < inputNames.length) {
406 if (lhm1.containsKey(inputNames[index])) {
407 Object value = lhm1.get(inputNames[index]);
408 if (value instanceof Map) {
409 if (index == inputNames.length - 1) {
410 ((Map) value).put(GET_INPUT, inputName);
414 return createInputValue((Map) value, index, inputNames, inputName);
417 Map<String, Object> jobProp = new HashMap<>();
418 if (index == inputNames.length - 1) {
419 jobProp.put(GET_INPUT, inputName);
420 lhm1.put(inputNames[index], jobProp);
423 lhm1.put(inputNames[index], jobProp);
425 return createInputValue(jobProp, index, inputNames, inputName);
429 Map<String, Object> jobProp = new HashMap<>();
430 lhm1.put(inputNames[index], jobProp);
431 if (index == inputNames.length - 1) {
432 jobProp.put(GET_INPUT, inputName);
436 return createInputValue(jobProp, index, inputNames, inputName);
443 Either<InputDefinition, ResponseFormat> prepareValueBeforeDelete(InputDefinition inputForDelete, PropertyDataDefinition inputValue,
444 List<String> pathOfComponentInstances) {
445 Either<InputDefinition, ResponseFormat> deleteEither = prepareValueBeforeDelete(inputForDelete, inputValue);
446 Either<String, JanusGraphOperationStatus> findDefaultValue = propertyOperation
447 .findDefaultValueFromSecondPosition(pathOfComponentInstances, inputValue.getUniqueId(), (String) inputValue.getDefaultValue());
448 if (findDefaultValue.isRight()) {
449 deleteEither = Either.right(componentsUtils.getResponseFormat(componentsUtils
450 .convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(findDefaultValue.right().value()))));
453 String defaultValue = findDefaultValue.left().value();
454 inputValue.setDefaultValue(defaultValue);
455 log.debug("The returned default value in ResourceInstanceProperty is {}", defaultValue);
459 Either<InputDefinition, ResponseFormat> prepareValueBeforeDeleteOfCapProp(InputDefinition inputForDelete, PropertyDataDefinition inputValue) {
460 Either<InputDefinition, ResponseFormat> deleteEither = prepareValueBeforeDelete(inputForDelete, inputValue);
461 inputValue.setDefaultValue(inputForDelete.getDefaultValue());
462 log.debug("The returned default value in ResourceInstanceProperty is {}", inputForDelete.getDefaultValue());
466 private Either<InputDefinition, ResponseFormat> prepareValueBeforeDelete(InputDefinition inputForDelete, PropertyDataDefinition inputValue) {
467 Either<InputDefinition, ResponseFormat> deleteEither = Either.left(inputForDelete);
468 String value = inputValue.getValue();
469 Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(value);
470 resetInputName(mappedToscaTemplate, inputForDelete.getName());
472 if (!mappedToscaTemplate.isEmpty()) {
473 Either result = cleanNestedMap(mappedToscaTemplate, true);
474 Map modifiedMappedToscaTemplate = mappedToscaTemplate;
475 if (result.isLeft()) {
476 modifiedMappedToscaTemplate = (Map) result.left().value();
478 log.warn("Map cleanup failed -> " + result.right().value()
479 .toString()); //continue, don't break operation
481 value = gson.toJson(modifiedMappedToscaTemplate);
483 inputValue.setValue(value);
484 List<GetInputValueDataDefinition> getInputsValues = inputValue.getGetInputValues();
485 if (getInputsValues != null && !getInputsValues.isEmpty()) {
486 Optional<GetInputValueDataDefinition> op = getInputsValues.stream().filter(gi -> gi.getInputId().equals(inputForDelete.getUniqueId()))
488 op.ifPresent(getInputsValues::remove);
490 inputValue.setGetInputValues(getInputsValues);
491 if (CollectionUtils.isEmpty(inputValue.getGetInputValues()) && inputValue.getToscaFunction() != null) {
492 inputValue.setToscaFunction(null);
497 private void resetInputName(Map<String, Object> lhm1, String inputName) {
498 for (Map.Entry<String, Object> entry : lhm1.entrySet()) {
499 String key = entry.getKey();
500 Object value = entry.getValue();
501 if (value instanceof String && ((String) value).equalsIgnoreCase(inputName) && key.equals(GET_INPUT)) {
503 } else if (value instanceof Map) {
504 Map<String, Object> subMap = (Map<String, Object>) value;
505 resetInputName(subMap, inputName);
506 } 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();
521 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)) {
539 if (MapUtils.isNotEmpty((Map) toscaElement)) {
541 Set<Object> keysToRemove = new HashSet<>(); // use different set to avoid ConcurrentModificationException
542 for (Object key : ((Map) toscaElement).keySet()) {
543 Object value = ((Map) toscaElement).get(key);
544 ret = cleanEmptyNestedValuesInMap(value, --loopProtectionLevel);
546 keysToRemove.add(key);
549 Collection set = ((Map) toscaElement).keySet();
550 if (CollectionUtils.isNotEmpty(set)) {
551 set.removeAll(keysToRemove);
553 if (isEmptyNestedMap(toscaElement)) {
562 //ignores other collection objects
563 private boolean isEmptyNestedMap(Object element) {
564 boolean isEmpty = true;
565 if (element != null) {
566 if (element instanceof Map) {
567 if (MapUtils.isEmpty((Map) element)) {
570 for (Object key : ((Map) (element)).keySet()) {
571 Object value = ((Map) (element)).get(key);
572 isEmpty &= isEmptyNestedMap(value);
581 //@returns true iff map nested maps are all empty
583 private class PropertiesDeclarationData {
585 private List<InputDefinition> inputsToCreate;
586 private List<PolicyDefinition> policiesToCreate;
587 private List<PROPERTYTYPE> propertiesToUpdate;
589 PropertiesDeclarationData(List<InputDefinition> inputsToCreate, List<PolicyDefinition> policiesToCreate,
590 List<PROPERTYTYPE> propertiesToUpdate) {
591 this.inputsToCreate = inputsToCreate;
592 this.policiesToCreate = policiesToCreate;
593 this.propertiesToUpdate = propertiesToUpdate;
596 List<InputDefinition> getInputsToCreate() {
597 return inputsToCreate;
600 public List<PolicyDefinition> getPoliciesToCreate() {
601 return policiesToCreate;
604 List<PROPERTYTYPE> getPropertiesToUpdate() {
605 return propertiesToUpdate;