diff options
author | Talio <tali.orenbach@amdocs.com> | 2019-01-31 18:00:36 +0200 |
---|---|---|
committer | Avi Gaffa <avi.gaffa@amdocs.com> | 2019-02-04 11:00:09 +0000 |
commit | 0953785bfd6a3af5e506f8a55a8520c0fb7ef358 (patch) | |
tree | 2f900e3f09a60a5a9a75ddcdd30930d3164eeeed /catalog-be/src/main/java | |
parent | 47c8af4d7241f20755ea97a6119bae2f500cfffa (diff) |
Add property mapping feature to ONAP
Add service property assignment
Change-Id: I29748ce12bacab06b8bc27f8875b39d80ffe5af7
Issue-ID: SDC-1988
Signed-off-by: Talio <tali.orenbach@amdocs.com>
Diffstat (limited to 'catalog-be/src/main/java')
16 files changed, 1427 insertions, 619 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java index 5f40606177..f49f531e28 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/PropertyBusinessLogic.java @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,19 +22,27 @@ package org.openecomp.sdc.be.components.impl; import com.google.gson.JsonElement; import fj.data.Either; +import java.util.Map.Entry; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstanceInterface; +import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.IComplexDefaultValue; +import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.PropertyDefinition; -import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.operations.api.IElementOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; @@ -45,17 +53,13 @@ import org.openecomp.sdc.be.resources.data.EntryData; import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; -import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; import javax.servlet.ServletContext; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; +import java.util.*; import java.util.function.Supplier; -@Component("propertyBusinessLogic") +@org.springframework.stereotype.Component("propertyBusinessLogic") public class PropertyBusinessLogic extends BaseBusinessLogic { private static final String CREATE_PROPERTY = "CreateProperty"; @@ -77,262 +81,368 @@ public class PropertyBusinessLogic extends BaseBusinessLogic { } /** - * Create new property on resource in graph + * Create new property on component in graph * - * @param resourceId + * @param componentId * @param propertyName * @param newPropertyDefinition * @param userId * @return either properties or response format */ - public Either<EntryData<String, PropertyDefinition>, ResponseFormat> createProperty(String resourceId, String propertyName, PropertyDefinition newPropertyDefinition, String userId) { + public Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyToComponent(String componentId, + String propertyName, + PropertyDefinition newPropertyDefinition, + String userId) { Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null; validateUserExists(userId, "create Property", false); - StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + Either<Component, StorageOperationStatus> serviceElement = + toscaOperationFacade.getToscaElement(componentId); + if (serviceElement.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + return result; + } + Component component = serviceElement.left().value(); + NodeTypeEnum nodeType = component.getComponentType().getNodeType(); + StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType ); if (!lockResult.equals(StorageOperationStatus.OK)) { - BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); - log.info("Failed to lock component {}. Error - {}", resourceId, lockResult); + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(), componentId); + log.info("Failed to lock component {}. Error - {}", componentId, lockResult); result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); return result; } try { - // Get the resource from DB - Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId); - if (status.isRight()) { - result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); - return result; - } - Resource resource = status.left().value(); - - // verify that resource is checked-out and the user is the last - // updater - if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) { result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); return result; } - // verify property not exist in resource - List<PropertyDefinition> resourceProperties = resource.getProperties(); + List<PropertyDefinition> properties = component.getProperties(); - if (resourceProperties != null && isPropertyExist(resourceProperties, resourceId, propertyName, newPropertyDefinition.getType())) { - result = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_ALREADY_EXIST, propertyName)); - return result; + if(CollectionUtils.isEmpty(properties)) { + properties = new ArrayList<>(); } - Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache); - if (allDataTypes.isRight()) { - result = Either.right(allDataTypes.right().value()); + if(isPropertyExistInComponent(properties, propertyName)) { + + result = + Either.right(componentsUtils.getResponseFormat(ActionStatus + .PROPERTY_ALREADY_EXIST, propertyName)); return result; - } - Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value(); + } else { - // validate property default values - Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newPropertyDefinition, dataTypes); - if (defaultValuesValidation.isRight()) { - result = Either.right(defaultValuesValidation.right().value()); - return result; - } - convertProperty(newPropertyDefinition, allDataTypes); + Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache); + if (allDataTypes.isRight()) { + result = Either.right(allDataTypes.right().value()); + return result; + } + Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value(); - // add the new property to resource on graph - // need to get StorageOpaerationStatus and convert to ActionStatus - // from componentsUtils - Either<PropertyDefinition, StorageOperationStatus> either = toscaOperationFacade.addPropertyToResource(propertyName, newPropertyDefinition, resource); - if (either.isRight()) { - result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName())); - return result; + // validate property default values + Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newPropertyDefinition, dataTypes); + if (defaultValuesValidation.isRight()) { + result = Either.right(defaultValuesValidation.right().value()); + return result; + } + // convert property + ToscaPropertyType type = getType(newPropertyDefinition.getType()); + if (type != null) { + PropertyValueConverter converter = type.getConverter(); + // get inner type + String innerType = null; + if (newPropertyDefinition != null) { + SchemaDefinition schema = newPropertyDefinition.getSchema(); + if (schema != null) { + PropertyDataDefinition prop = schema.getProperty(); + if (prop != null) { + innerType = prop.getType(); + } + } + String convertedValue = null; + if (newPropertyDefinition.getDefaultValue() != null) { + convertedValue = converter.convert( + (String) newPropertyDefinition.getDefaultValue(), innerType, allDataTypes.left().value()); + newPropertyDefinition.setDefaultValue(convertedValue); + } + } + } + Either<PropertyDefinition, StorageOperationStatus> addPropertyEither = + toscaOperationFacade + .addPropertyToComponent(propertyName, newPropertyDefinition, component); + + if (addPropertyEither.isRight()) { + log.info("Failed to add new property {}. Error - {}", componentId, + addPropertyEither.right().value()); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus + .GENERAL_ERROR)); + return result; + } } - PropertyDefinition createdPropertyDefinition = either.left().value(); - EntryData<String, PropertyDefinition> property = new EntryData<>(propertyName, createdPropertyDefinition); - result = Either.left(property); + result = Either.left(new EntryData<>(propertyName, newPropertyDefinition)); return result; } finally { commitOrRollback(result); // unlock component - graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + graphLockOperation.unlockComponent(componentId, nodeType); } } - private void convertProperty(PropertyDefinition newPropertyDefinition, Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes) { - ToscaPropertyType type = getType(newPropertyDefinition.getType()); - if (type != null) { - String innerType = null; - SchemaDefinition schema = newPropertyDefinition.getSchema(); - if (schema != null && schema.getProperty() != null) { - innerType = schema.getProperty().getType(); - } - if (newPropertyDefinition.getDefaultValue() != null) { - newPropertyDefinition.setDefaultValue( - type.getConverter().convert( - newPropertyDefinition.getDefaultValue(), innerType, allDataTypes.left().value())); - } - } - } - /** - * Get property of resource + * Get property of component * - * @param resourceId + * @param componentId * @param propertyId * @param userId * @return either properties or response format */ - public Either<Entry<String, PropertyDefinition>, ResponseFormat> getProperty(String resourceId, String propertyId, String userId) { + + public Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> getComponentProperty(String componentId, String propertyId, String userId) { validateUserExists(userId, "create Component Instance", false); // Get the resource from DB - Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId); + Either<Component, StorageOperationStatus> status = + toscaOperationFacade.getToscaElement(componentId); if (status.isRight()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); } - Resource resource = status.left().value(); - - // verify property exist in resource - List<PropertyDefinition> properties = resource.getProperties(); - if (properties == null) { + Component component = status.left().value(); + List<PropertyDefinition> properties = component.getProperties(); + if(CollectionUtils.isEmpty(properties)) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, "")); } - for (PropertyDefinition property : properties) { - if (property.getUniqueId().equals(propertyId) ) { - Map<String, PropertyDefinition> propMap = new HashMap<>(); - propMap.put(property.getName(), property); - return Either.left(propMap.entrySet().iterator().next()); + + for(PropertyDefinition property : properties) { + if(property.getUniqueId().equals(propertyId)) { + return Either.left(new EntryData<>(property.getName(), property)); } } return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, "")); } + + public Either<List<PropertyDefinition>, ResponseFormat> getPropertiesList(String componentId, + String userId) { + validateUserExists(userId, "create Component Instance", false); + + // Get the resource from DB + ComponentParametersView filter = new ComponentParametersView(true); + filter.setIgnoreProperties(false); + Either<Component, StorageOperationStatus> status = + toscaOperationFacade.getToscaElement(componentId); + if (status.isRight()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + } + Component component = status.left().value(); + List<PropertyDefinition> properties = component.getProperties(); + + return Either.left(properties); + } + + /** - * delete property of resource from graph + * delete property of component from graph * - * @param resourceId + * @param componentId * @param propertyId * @param userId * @return either properties or response format */ - public Either<Entry<String, PropertyDefinition>, ResponseFormat> deleteProperty(String resourceId, String propertyId, String userId) { - Either<Entry<String, PropertyDefinition>, ResponseFormat> result = null; + public Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> deletePropertyFromComponent(String componentId, String propertyId, String userId) { + + Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> result = null; validateUserExists(userId, "delete Property", false); - StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + // Get the resource from DB + Either<Component, StorageOperationStatus> getComponentRes = toscaOperationFacade.getToscaElement(componentId); + if (getComponentRes.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); + return result; + } + Component component = getComponentRes.left().value(); + NodeTypeEnum nodeType = component.getComponentType().getNodeType(); + StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType); if (!lockResult.equals(StorageOperationStatus.OK)) { - BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(), + componentId); result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); return result; } try { - - // Get the resource from DB - Either<Resource, StorageOperationStatus> getResourceRes = toscaOperationFacade.getToscaElement(resourceId); - if (getResourceRes.isRight()) { - result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); - return result; - } - Resource resource = getResourceRes.left().value(); - // verify that resource is checked-out and the user is the last // updater - if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) { result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); return result; } // verify property exist in resource - Either<Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty = getProperty(resourceId, propertyId, userId); + Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty = + getComponentProperty(componentId, propertyId, userId); if (statusGetProperty.isRight()) { result = Either.right(statusGetProperty.right().value()); return result; } - StorageOperationStatus status = toscaOperationFacade.deletePropertyOfResource(resource, statusGetProperty.left().value().getKey()); + Map.Entry<String, PropertyDefinition> propertyDefinitionEntry = statusGetProperty.left().value(); + + // verify that the property is not used by operation + if (isPropertyUsedByOperation(component, propertyDefinitionEntry.getValue())) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .PROPERTY_USED_BY_OPERATION)); + } + + StorageOperationStatus status = + toscaOperationFacade.deletePropertyOfComponent(component, propertyDefinitionEntry.getKey()); if (status != StorageOperationStatus.OK) { - result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status), resource.getName())); + result = Either.right(componentsUtils.getResponseFormat(componentsUtils + .convertFromStorageResponse(status), component.getName())); return result; } - result = Either.left(statusGetProperty.left().value()); + result = Either.left(propertyDefinitionEntry); return result; } finally { commitOrRollback(result); // unlock component - graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + graphLockOperation.unlockComponent(componentId, nodeType); + } + } + + public boolean isPropertyUsedByOperation(Component component, + PropertyDefinition propertyDefinitionEntry) { + + // Component's own interfaces + Map<String, InterfaceDefinition> interfaces = component.getInterfaces(); + if(MapUtils.isNotEmpty(interfaces)){ + for(Map.Entry<String, InterfaceDefinition> interfaceEntry : interfaces.entrySet()) { + if (isPropertyExistInOperationInterface(propertyDefinitionEntry, interfaceEntry.getValue())) { + return true; + } + } + } + + // Component's child's component interfaces + if(isPropertyUsedInCIInterfaces(component.getComponentInstancesInterfaces(), propertyDefinitionEntry)){ + return true; + } + + // Component's parent's component interfaces + Either<List<Component>, StorageOperationStatus> componentList = toscaOperationFacade.getParentComponents(component.getUniqueId()); + if(componentList.isLeft()){ + for (Component parentComponent : componentList.left().value()) { + if(isPropertyUsedInCIInterfaces(parentComponent.getComponentInstancesInterfaces(), propertyDefinitionEntry)){ + return true; + } + } + } + + return false; + } + + private boolean isPropertyUsedInCIInterfaces(Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces, PropertyDefinition propertyDefinitionEntry){ + if(MapUtils.isNotEmpty(componentInstanceInterfaces)){ + for (Entry<String, List<ComponentInstanceInterface>> interfaceEntry : componentInstanceInterfaces.entrySet()) { + for (ComponentInstanceInterface instanceInterface : interfaceEntry.getValue()) { + if (isPropertyExistInOperationInterface(propertyDefinitionEntry, instanceInterface)) { + return true; + } + } + } } + return false; + } + + private boolean isPropertyExistInOperationInterface(PropertyDefinition propertyDefinition, + InterfaceDefinition interfaceDefinition) { + Map<String, OperationDataDefinition> operations = + interfaceDefinition.getOperations(); + for(Map.Entry<String, OperationDataDefinition> operationEntry : operations + .entrySet()) { + Optional<OperationInputDefinition> inputWithDeletedPropertyCandidate = + getInputWithDeclaredProperty(propertyDefinition, operationEntry); + + if(inputWithDeletedPropertyCandidate.isPresent()) { + return true; + } + } + return false; + } + + private Optional<OperationInputDefinition> getInputWithDeclaredProperty(PropertyDefinition propertyDefinition, + Map.Entry<String, OperationDataDefinition> operationEntry) { + ListDataDefinition<OperationInputDefinition> inputs = + operationEntry.getValue().getInputs(); + List<OperationInputDefinition> operationInputsList = + Objects.isNull(inputs) ? null : inputs.getListToscaDataDefinition(); + + if(CollectionUtils.isEmpty(operationInputsList)) { + return Optional.empty(); + } + + return operationInputsList.stream().filter(input -> input.getInputId().equals(propertyDefinition.getUniqueId())).findAny(); } /** * update property * - * @param resourceId + * @param componentId * @param propertyId * @param newPropertyDefinition * @param userId * @return either properties or response format */ - public Either<EntryData<String, PropertyDefinition>, ResponseFormat> updateProperty(String resourceId, String propertyId, PropertyDefinition newPropertyDefinition, String userId) { + + public Either<EntryData<String, PropertyDefinition>, ResponseFormat> updateComponentProperty(String componentId, + String propertyId, + PropertyDefinition newPropertyDefinition, + String userId) { Either<EntryData<String, PropertyDefinition>, ResponseFormat> result = null; - Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId); + Either<Component, StorageOperationStatus> status = toscaOperationFacade.getToscaElement( + componentId); if (status.isRight()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, "")); } - Resource resource = status.left().value(); + Component component = status.left().value(); + NodeTypeEnum nodeType = component.getComponentType().getNodeType(); - if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) { + if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); } - StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); + StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType); if (!lockResult.equals(StorageOperationStatus.OK)) { - BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, NodeTypeEnum.Resource.name().toLowerCase(), resourceId); + BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_PROPERTY, nodeType.name().toLowerCase(), + componentId); result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); return result; } try { - Either<Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty = getProperty(resourceId, propertyId, userId); + Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> statusGetProperty = + getComponentProperty(componentId, propertyId, userId); if (statusGetProperty.isRight()) { result = Either.right(statusGetProperty.right().value()); return result; } String propertyName = statusGetProperty.left().value().getKey(); - Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache); - if (allDataTypes.isRight()) { - result = Either.right(allDataTypes.right().value()); - return result; - } - Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value(); - - Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newPropertyDefinition, dataTypes); - if (defaultValuesValidation.isRight()) { - result = Either.right(defaultValuesValidation.right().value()); - return result; - } - - Either<PropertyDefinition, StorageOperationStatus> either = handleProperty(newPropertyDefinition, dataTypes); - if (either.isRight()) { - log.debug("Problem while updating property with id {}. Reason - {}", propertyId, either.right().value()); - result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName())); - return result; - } - - - either = toscaOperationFacade.updatePropertyOfResource(resource, newPropertyDefinition); + Either<PropertyDefinition, StorageOperationStatus> either = + toscaOperationFacade.updatePropertyOfComponent(component, newPropertyDefinition); if (either.isRight()) { - result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName())); + result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(either.right().value()), component.getName())); return result; } @@ -342,18 +452,30 @@ public class PropertyBusinessLogic extends BaseBusinessLogic { } finally { commitOrRollback(result); - graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource); + graphLockOperation.unlockComponent(componentId, nodeType); } } + private boolean isPropertyExistInComponent(List<PropertyDefinition> properties, String propertyName) { + if(CollectionUtils.isEmpty(properties)) { + return false; + } + + Optional<PropertyDefinition> propertyCandidate = + properties.stream().filter(property -> property.getName().equals(propertyName)) + .findAny(); + + return propertyCandidate.isPresent(); + } + private boolean isPropertyExist(List<PropertyDefinition> properties, String resourceUid, String propertyName, String propertyType) { boolean result = false; if (!CollectionUtils.isEmpty(properties)) { for (PropertyDefinition propertyDefinition : properties) { if ( propertyDefinition.getName().equals(propertyName) && - (propertyDefinition.getParentUniqueId().equals(resourceUid) || !propertyDefinition.getType().equals(propertyType)) ) { + (propertyDefinition.getParentUniqueId().equals(resourceUid) || !propertyDefinition.getType().equals(propertyType)) ) { result = true; break; } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentPropertyDeclarator.java new file mode 100644 index 0000000000..7f49e389ef --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/ComponentPropertyDeclarator.java @@ -0,0 +1,153 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.components.property; + +import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; +import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; +import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +@org.springframework.stereotype.Component +public class ComponentPropertyDeclarator extends DefaultPropertyDeclarator<Component, PropertyDataDefinition> { + + private ToscaOperationFacade toscaOperationFacade; + PropertyBusinessLogic propertyBL; + + + public ComponentPropertyDeclarator(ComponentsUtils componentsUtils, + PropertyOperation propertyOperation, + ToscaOperationFacade toscaOperationFacade, + PropertyBusinessLogic propertyBL) { + super(componentsUtils, propertyOperation); + this.toscaOperationFacade = toscaOperationFacade; + this.propertyBL = propertyBL; + } + + @Override + PropertyDataDefinition createDeclaredProperty(PropertyDataDefinition prop) { + return new PropertyDataDefinition(prop); + } + + @Override + Either<?, StorageOperationStatus> updatePropertiesValues(Component component, + String propertiesOwnerId, + List<PropertyDataDefinition> properties) { + if(CollectionUtils.isNotEmpty(properties)) { + for(PropertyDataDefinition property : properties) { + Either<PropertyDefinition, StorageOperationStatus> + storageStatus = toscaOperationFacade + .updatePropertyOfComponent(component, new PropertyDefinition(property)); + if(storageStatus.isRight()) { + return Either.right(storageStatus.right().value()); + } + } + } + return Either.left(properties); + } + + @Override + Optional<Component> resolvePropertiesOwner(Component component, String propertiesOwnerId) { + return Optional.of( component); + } + + @Override + void addPropertiesListToInput(PropertyDataDefinition declaredProp, + InputDefinition input) { + + List<ComponentInstanceProperty> propertiesList = input.getProperties(); + if(propertiesList == null) { + propertiesList = new ArrayList<>(); // adding the property with the new value for UI + } + propertiesList.add(new ComponentInstanceProperty(declaredProp)); + input.setProperties(propertiesList); + } + + @Override + public StorageOperationStatus unDeclarePropertiesAsInputs(Component component, + InputDefinition input) { + PropertyDefinition propertyDefinition = new PropertyDefinition(input); + + if(propertyBL.isPropertyUsedByOperation(component, propertyDefinition)) { + return StorageOperationStatus.DECLARED_INPUT_USED_BY_OPERATION; + } + + Optional<PropertyDefinition> propertyToUpdateCandidate = + getDeclaredPropertyByInputId(component, input.getUniqueId()); + + if(propertyToUpdateCandidate.isPresent()) { + PropertyDefinition propertyToUpdate = propertyToUpdateCandidate.get(); + return unDeclareInput(component, input, propertyToUpdate); + } + + + return StorageOperationStatus.OK; + } + + private StorageOperationStatus unDeclareInput(Component component, + InputDefinition input, + PropertyDefinition propertyToUpdate) { + prepareValueBeforeDelete(input, propertyToUpdate, Collections.emptyList()); + propertyToUpdate.setValue(input.getDefaultValue()); + Either<PropertyDefinition, StorageOperationStatus> status = toscaOperationFacade + .updatePropertyOfComponent(component, propertyToUpdate); + if(status.isRight()) { + return status.right().value(); + } + + return StorageOperationStatus.OK; + } + + private Optional<PropertyDefinition> getDeclaredPropertyByInputId(Component component, + String inputId) { + List<PropertyDefinition> properties = component.getProperties(); + + if(CollectionUtils.isEmpty(properties)) { + return Optional.empty(); + } + + for(PropertyDefinition propertyDefinition : properties) { + List<GetInputValueDataDefinition> getInputValues = propertyDefinition.getGetInputValues(); + if(CollectionUtils.isEmpty(getInputValues)) { + continue; + } + + Optional<GetInputValueDataDefinition> getInputCandidate = + getInputValues.stream().filter(getInput -> getInput.getInputId().equals(inputId)) + .findAny(); + + if(getInputCandidate.isPresent()) { + return Optional.of(propertyDefinition); + } + } + + return Optional.empty(); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java index a5ba0003d2..437ae2d67d 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java @@ -87,20 +87,44 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties } private InputDefinition createInput(String componentId, PROPERTYOWNER propertiesOwner, ComponentInstancePropInput propInput, PropertyDataDefinition prop) { - String generatedInputName = generateInputName(propertiesOwner.getNormalizedName(), propInput); + String generatedInputName = generateInputName(propertiesOwner instanceof + Service ? null : propertiesOwner.getNormalizedName(), + propInput); return createInputFromProperty(componentId, propertiesOwner, generatedInputName, propInput, prop); } private String generateInputName(String inputName, ComponentInstancePropInput propInput) { + String declaredInputName = inputName; String[] parsedPropNames = propInput.getParsedPropNames(); + if(parsedPropNames != null){ - for(String str: parsedPropNames){ - inputName += "_" + str; - } + declaredInputName = handleInputName(inputName, parsedPropNames); } else { - inputName += "_" + propInput.getName(); + String[] propName = {propInput.getName()}; + declaredInputName = handleInputName(inputName, propName); } - return inputName; + + return declaredInputName; + } + + private String handleInputName(String inputName, String[] parsedPropNames) { + String prefix; + int startingIndex; + + if(Objects.isNull(inputName)) { + prefix = parsedPropNames[0]; + startingIndex = 1; + } else { + prefix = inputName; + startingIndex = 0; + } + + while(startingIndex < parsedPropNames.length){ + prefix += "_" + parsedPropNames[startingIndex]; + startingIndex ++; + } + + return prefix; } private PropertyDataDefinition resolveProperty(List<PROPERTYTYPE> propertiesToCreate, ComponentInstancePropInput propInput) { @@ -131,14 +155,20 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties input.setPropertyId(propInput.getUniqueId()); input.setValue(null); changePropertyValueToGetInputValue(inputName, parsedPropNames, input, prop, complexProperty); - ((IComponentInstanceConnectedElement)prop).setComponentInstanceId(propertiesOwner.getUniqueId()); - ((IComponentInstanceConnectedElement)prop).setComponentInstanceName(propertiesOwner.getName()); + + if(prop instanceof IComponentInstanceConnectedElement) { + ((IComponentInstanceConnectedElement) prop) + .setComponentInstanceId(propertiesOwner.getUniqueId()); + ((IComponentInstanceConnectedElement) prop) + .setComponentInstanceName(propertiesOwner.getName()); + } return input; } private void changePropertyValueToGetInputValue(String inputName, String[] parsedPropNames, InputDefinition input, PropertyDataDefinition prop, boolean complexProperty) { JSONObject jobject = new JSONObject(); - if(prop.getValue() == null || prop.getValue().isEmpty()){ + String value = (String) prop.getValue(); + if(value == null || value.isEmpty()){ if(complexProperty){ jobject = createJSONValueForProperty(parsedPropNames.length -1, parsedPropNames, jobject, inputName); @@ -153,7 +183,7 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties }else{ - String value = prop.getValue(); + //String value = value; Object objValue = new Yaml().load(value); if( objValue instanceof Map || objValue instanceof List){ if(!complexProperty){ diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarationOrchestrator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarationOrchestrator.java index 937e2ccfc8..babddc4da1 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarationOrchestrator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/PropertyDeclarationOrchestrator.java @@ -22,14 +22,21 @@ public class PropertyDeclarationOrchestrator { private ComponentInstancePropertyDeclarator componentInstancePropertyDeclarator; private PolicyPropertyDeclarator policyPropertyDeclarator; private GroupPropertyDeclarator groupPropertyDeclarator; + private ComponentPropertyDeclarator servicePropertyDeclarator; private List<PropertyDeclarator> propertyDeclarators; - public PropertyDeclarationOrchestrator(ComponentInstanceInputPropertyDeclarator componentInstanceInputPropertyDeclarator, ComponentInstancePropertyDeclarator componentInstancePropertyDeclarator, PolicyPropertyDeclarator policyPropertyDeclarator, GroupPropertyDeclarator groupPropertyDeclarator) { + public PropertyDeclarationOrchestrator( + ComponentInstanceInputPropertyDeclarator componentInstanceInputPropertyDeclarator, + ComponentInstancePropertyDeclarator componentInstancePropertyDeclarator, + PolicyPropertyDeclarator policyPropertyDeclarator, + GroupPropertyDeclarator groupPropertyDeclarator, + ComponentPropertyDeclarator servicePropertyDeclarator) { this.componentInstanceInputPropertyDeclarator = componentInstanceInputPropertyDeclarator; this.componentInstancePropertyDeclarator = componentInstancePropertyDeclarator; this.policyPropertyDeclarator = policyPropertyDeclarator; this.groupPropertyDeclarator = groupPropertyDeclarator; - propertyDeclarators = Arrays.asList(componentInstanceInputPropertyDeclarator, componentInstancePropertyDeclarator, policyPropertyDeclarator, groupPropertyDeclarator); + this.servicePropertyDeclarator = servicePropertyDeclarator; + propertyDeclarators = Arrays.asList(componentInstanceInputPropertyDeclarator, componentInstancePropertyDeclarator, policyPropertyDeclarator, groupPropertyDeclarator, servicePropertyDeclarator); } public Either<List<InputDefinition>, StorageOperationStatus> declarePropertiesToInputs(Component component, ComponentInstInputsMap componentInstInputsMap) { @@ -64,6 +71,9 @@ public class PropertyDeclarationOrchestrator { if (isNotEmpty(componentInstInputsMap.getGroupProperties())) { return groupPropertyDeclarator; } + if(isNotEmpty(componentInstInputsMap.getServiceProperties())) { + return servicePropertyDeclarator; + } throw new IllegalStateException("there are no properties selected for declaration"); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java index 5b8d6dcc17..4502012bd9 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java @@ -23,8 +23,27 @@ package org.openecomp.sdc.be.servlets; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; import fj.data.Either; -import org.openecomp.sdc.be.components.impl.*; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ElementBusinessLogic; +import org.openecomp.sdc.be.components.impl.GroupBusinessLogic; +import org.openecomp.sdc.be.components.impl.InterfaceOperationBusinessLogic; +import org.openecomp.sdc.be.components.impl.MonitoringBusinessLogic; +import org.openecomp.sdc.be.components.impl.PolicyBusinessLogic; +import org.openecomp.sdc.be.components.impl.PolicyTypeBusinessLogic; +import org.openecomp.sdc.be.components.impl.ProductBusinessLogic; +import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; +import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic; +import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic; import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic; import org.openecomp.sdc.be.components.scheduledtasks.ComponentsCleanBusinessLogic; import org.openecomp.sdc.be.components.upgrade.UpgradeBusinessLogic; @@ -35,8 +54,11 @@ import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter; import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.impl.WebAppContextWrapper; import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintJacksonDeserializer; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; import org.openecomp.sdc.be.user.UserBusinessLogic; import org.openecomp.sdc.common.api.Constants; @@ -51,8 +73,12 @@ import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.function.Supplier; public class BeGenericServlet extends BasicServlet { @@ -79,8 +105,8 @@ public class BeGenericServlet extends BasicServlet { private static Response buildOkResponseStatic(Object entity) { return Response.status(Response.Status.OK) - .entity(entity) - .build(); + .entity(entity) + .build(); } protected Response buildOkResponse(ResponseFormat errorResponseWrapper, Object entity) { @@ -215,8 +241,8 @@ public class BeGenericServlet extends BasicServlet { protected String getContentDispositionValue(String artifactFileName) { return new StringBuilder().append("attachment; filename=\"").append(artifactFileName).append("\"").toString(); } - - + + protected ComponentBusinessLogic getComponentBL(ComponentTypeEnum componentTypeEnum, ServletContext context) { ComponentBusinessLogic businessLogic; @@ -243,8 +269,8 @@ public class BeGenericServlet extends BasicServlet { <T> void convertJsonToObjectOfClass(String json, Wrapper<T> policyWrapper, Class<T> clazz, Wrapper<Response> errorWrapper) { T object = null; ObjectMapper mapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); try { log.trace("Starting to convert json to object. Json=\n{}", json); @@ -266,4 +292,143 @@ public class BeGenericServlet extends BasicServlet { errorWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT))); } } + + protected Either<Map<String, PropertyDefinition>, ActionStatus> getPropertyModel(String componentId, + String data) { + JSONParser parser = new JSONParser(); + JSONObject root; + try { + Map<String, PropertyDefinition> properties = new HashMap<String, PropertyDefinition>(); + root = (JSONObject) parser.parse(data); + + Set entrySet = root.entrySet(); + Iterator iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Entry next = (Entry) iterator.next(); + String propertyName = (String) next.getKey(); + JSONObject value = (JSONObject) next.getValue(); + String jsonString = value.toJSONString(); + Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(jsonString, PropertyDefinition.class); + if (convertJsonToObject.isRight()) { + return Either.right(convertJsonToObject.right().value()); + } + PropertyDefinition propertyDefinition = convertJsonToObject.left().value(); + String uniqueId = UniqueIdBuilder.buildPropertyUniqueId(componentId, (String) propertyName); + propertyDefinition.setUniqueId(uniqueId); + properties.put(propertyName, propertyDefinition); + } + + return Either.left(properties); + } catch (ParseException e) { + log.info("Property conetnt is invalid - {}", data); + return Either.right(ActionStatus.INVALID_CONTENT); + } + } + + protected Either<Map<String, PropertyDefinition>, ActionStatus> getPropertiesListForUpdate(String data) { + + Map<String, PropertyDefinition> properties = new HashMap<>(); + JSONParser parser = new JSONParser(); + JSONArray jsonArray; + + try { + jsonArray = (JSONArray) parser.parse(data); + for (Object jsonElement : jsonArray) { + String propertyAsString = jsonElement.toString(); + Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(propertyAsString, PropertyDefinition.class); + + if (convertJsonToObject.isRight()) { + return Either.right(convertJsonToObject.right().value()); + } + + PropertyDefinition propertyDefinition = convertJsonToObject.left().value(); + properties.put(propertyDefinition.getName(), propertyDefinition); + } + + return Either.left(properties); + } catch (Exception e) { + log.info("Property content is invalid - {}", data); + return Either.right(ActionStatus.INVALID_CONTENT); + } + + } + + + protected String propertyToJson(Map.Entry<String, PropertyDefinition> property) { + JSONObject root = new JSONObject(); + String propertyName = property.getKey(); + PropertyDefinition propertyDefinition = property.getValue(); + JSONObject propertyDefinitionO = getPropertyDefinitionJSONObject(propertyDefinition); + root.put(propertyName, propertyDefinitionO); + propertyDefinition.getType(); + return root.toString(); + } + + private JSONObject getPropertyDefinitionJSONObject(PropertyDefinition propertyDefinition) { + + Either<String, ActionStatus> either = convertObjectToJson(propertyDefinition); + if (either.isRight()) { + return new JSONObject(); + } + String value = either.left().value(); + try { + JSONObject root = (JSONObject) new JSONParser().parse(value); + return root; + } catch (ParseException e) { + log.info("failed to convert input to json"); + log.debug("failed to convert to json", e); + return new JSONObject(); + } + + } + + protected <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) { + T t = null; + Type constraintType = new TypeToken<PropertyConstraint>() { + }.getType(); + Gson + gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyOperation.PropertyConstraintDeserialiser()).create(); + try { + log.trace("convert json to object. json=\n {}", data); + t = gson.fromJson(data, clazz); + if (t == null) { + log.info("object is null after converting from json"); + return Either.right(ActionStatus.INVALID_CONTENT); + } + } catch (Exception e) { + // INVALID JSON + log.info("failed to convert from json"); + log.debug("failed to convert from json", e); + return Either.right(ActionStatus.INVALID_CONTENT); + } + return Either.left(t); + } + + private <T> Either<String, ActionStatus> convertObjectToJson(PropertyDefinition propertyDefinition) { + Type constraintType = new TypeToken<PropertyConstraint>() { + }.getType(); + Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyOperation.PropertyConstraintSerialiser()).create(); + try { + log.trace("convert object to json. propertyDefinition= {}", propertyDefinition); + String json = gson.toJson(propertyDefinition); + if (json == null) { + log.info("object is null after converting to json"); + return Either.right(ActionStatus.INVALID_CONTENT); + } + return Either.left(json); + } catch (Exception e) { + // INVALID JSON + log.info("failed to convert to json"); + log.debug("failed to convert fto json", e); + return Either.right(ActionStatus.INVALID_CONTENT); + } + + } + + protected PropertyBusinessLogic getPropertyBL(ServletContext context) { + WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); + WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); + PropertyBusinessLogic propertytBl = webApplicationContext.getBean(PropertyBusinessLogic.class); + return propertytBl; + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java index 042303e2c3..b5e28148da 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java @@ -1139,7 +1139,7 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet { return Either.left(requirementCapabilityRelDef); } - private <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) { + public <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) { try { log.trace("convert json to object. json=\n {}", data); T t; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java new file mode 100644 index 0000000000..0edce61bae --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java @@ -0,0 +1,390 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.servlets; + +import com.jcabi.aspects.Loggable; +import fj.data.Either; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.EntryData; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; +import java.util.Map; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Api(value = "Component Property Servlet", description = "Property Servlet - used to create properties in Service and Resource") +@Singleton +public class ComponentPropertyServlet extends BeGenericServlet { + + private static final Logger log = LoggerFactory.getLogger(ComponentPropertyServlet.class); + + @POST + @Path("services/{serviceId}/properties") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Service Property", httpMethod = "POST", notes = "Returns created service property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Service property created"), + @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Service property already exist") }) + public Response createPropertyInService(@ApiParam(value = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId, + @ApiParam(value = "Service property to be created", required = true) String data, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return createProperty(serviceId, data, request, userId); + } + + @POST + @Path("resources/{resourceId}/properties") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Create Resource Property", httpMethod = "POST", notes = "Returns created service property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource property created"), + @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Resource property already exist") }) + public Response createPropertyInResource(@ApiParam(value = "Resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "Resource property to be created", required = true) String data, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return createProperty(resourceId, data, request, userId); + } + + + @GET + @Path("services/{serviceId}/properties/{propertyId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Service Property", httpMethod = "GET", notes = "Returns property of service", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Service property not found") }) + public Response getPropertyInService(@ApiParam(value = "service id of property", required = true) + @PathParam("serviceId") final String serviceId, @ApiParam(value = "property id to get", required = true) @PathParam("propertyId") final String propertyId, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return getProperty(serviceId, propertyId, request, userId); + } + + @GET + @Path("resources/{resourceId}/properties/{propertyId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Resource Property", httpMethod = "GET", notes = "Returns property of resource", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Resource property not found") }) + public Response getPropertyInResource(@ApiParam(value = "resource id of property", required = true) + @PathParam("resourceId") final String resourceId, @ApiParam(value = "property id to get", required = true) @PathParam("propertyId") final String propertyId, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return getProperty(resourceId, propertyId, request, userId); + } + + @GET + @Path("services/{serviceId}/properties") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Service Property", httpMethod = "GET", notes = "Returns property list of service", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Service property not found") }) + public Response getPropertyListInService(@ApiParam(value = "service id of property", required = true) @PathParam("serviceId") final String serviceId, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return getPropertyList(serviceId, request, userId); + } + + @GET + @Path("resources/{resourceId}/properties") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get Resource Property", httpMethod = "GET", notes = "Returns property list of resource", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Resource property not found") }) + public Response getPropertyListInResource(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return getPropertyList(resourceId, request, userId); + } + + @DELETE + @Path("services/{serviceId}/properties/{propertyId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete Service Property", httpMethod = "DELETE", notes = "Returns deleted property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "deleted property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Service property not found") }) + public Response deletePropertyInService(@ApiParam(value = "service id of property", required = true) @PathParam("serviceId") final String serviceId, + @ApiParam(value = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return deleteProperty(serviceId, propertyId, request, userId); + } + + @DELETE + @Path("resources/{resourceId}/properties/{propertyId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Delete Resource Property", httpMethod = "DELETE", notes = "Returns deleted property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 204, message = "deleted property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Resource property not found") }) + public Response deletePropertyInResource(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return deleteProperty(resourceId, propertyId, request, userId); + } + + @PUT + @Path("services/{serviceId}/properties") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Service Property", httpMethod = "PUT", notes = "Returns updated property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Service property updated"), + @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updatePropertyInService(@ApiParam(value = "service id to update with new property", required = true) @PathParam("serviceId") final String serviceId, + @ApiParam(value = "Service property to update", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return updateProperty(serviceId, data, request, userId); + } + + @PUT + @Path("resources/{resourceId}/properties") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update Resource Property", httpMethod = "PUT", notes = "Returns updated property", response = Response.class) + @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource property updated"), + @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) + public Response updatePropertyInResource(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, + @ApiParam(value = "Resource property to update", required = true) String data, @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return updateProperty(resourceId, data, request, userId); + } + + private Response createProperty(String componentId, String data, HttpServletRequest request,String userId) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data); + + try{ + Either<Map<String, PropertyDefinition>, ActionStatus> propertyDefinition = + getPropertyModel(componentId, data); + if (propertyDefinition.isRight()) { + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(propertyDefinition.right().value()); + return buildErrorResponse(responseFormat); + } + + Map<String, PropertyDefinition> properties = propertyDefinition.left().value(); + if (properties == null || properties.size() != 1) { + log.info("Property content is invalid - {}", data); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + return buildErrorResponse(responseFormat); + } + + Map.Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next(); + PropertyDefinition newPropertyDefinition = entry.getValue(); + newPropertyDefinition.setParentUniqueId(componentId); + String propertyName = newPropertyDefinition.getName(); + + PropertyBusinessLogic propertyBL = getPropertyBL(context); + Either<EntryData<String, PropertyDefinition>, ResponseFormat> addPropertyEither = + propertyBL.addPropertyToComponent(componentId, propertyName, newPropertyDefinition, userId); + + if(addPropertyEither.isRight()) { + return buildErrorResponse(addPropertyEither.right().value()); + } + + return buildOkResponse(newPropertyDefinition); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Property"); + log.debug("create property failed with exception", e); + ResponseFormat responseFormat = + getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } + + + private Response updateProperty(String componentId, String data, HttpServletRequest request, String userId) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {}", url); + + // get modifier id + User modifier = new User(); + modifier.setUserId(userId); + log.debug("modifier id is {}", userId); +// + try { + // convert json to PropertyDefinition + + Either<Map<String, PropertyDefinition>, ActionStatus> propertiesListEither = + getPropertiesListForUpdate(data); + if (propertiesListEither.isRight()) { + ResponseFormat responseFormat = + getComponentsUtils().getResponseFormat(propertiesListEither.right().value()); + return buildErrorResponse(responseFormat); + } + Map<String, PropertyDefinition> properties = propertiesListEither.left().value(); + if (properties == null) { + log.info("Property content is invalid - {}", data); + ResponseFormat responseFormat = + getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); + return buildErrorResponse(responseFormat); + } + + // update property + + PropertyBusinessLogic businessLogic = getPropertyBL(context); + for(PropertyDefinition propertyDefinition : properties.values()) { + Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = + businessLogic.updateComponentProperty( + componentId, propertyDefinition.getUniqueId(), propertyDefinition, userId); + if (status.isRight()) { + log.info("Failed to update Property. Reason - ", status.right().value()); + return buildErrorResponse(status.right().value()); + } + EntryData<String, PropertyDefinition> property = status.left().value(); + PropertyDefinition updatedPropertyDefinition = property.getValue(); + + log.debug("Property id {} updated successfully ", updatedPropertyDefinition.getUniqueId()); + } + + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); + return buildOkResponse(responseFormat, properties); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property"); + log.debug("update property failed with exception", e); + ResponseFormat responseFormat = + getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + + private Response getProperty(String componentId, String propertyId, HttpServletRequest request, String userId) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} modifier id is {}", url, userId); + + try { + PropertyBusinessLogic propertyBL = getPropertyBL(context); + Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> retrievedPropertyEither = + propertyBL.getComponentProperty(componentId, propertyId, userId); + + if(retrievedPropertyEither.isRight()) { + return buildErrorResponse(retrievedPropertyEither.right().value()); + } + + return buildOkResponse(retrievedPropertyEither.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Property"); + log.debug("get property failed with exception", e); + ResponseFormat responseFormat = + getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } + private Response getPropertyList(String componentId, HttpServletRequest request, String userId) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} modifier id is {}", url, userId); + + try { + PropertyBusinessLogic propertyBL = getPropertyBL(context); + Either<List<PropertyDefinition>, ResponseFormat> propertiesListEither = + propertyBL.getPropertiesList(componentId, userId); + + if(propertiesListEither.isRight()) { + return buildErrorResponse(propertiesListEither.right().value()); + } + + return buildOkResponse(propertiesListEither.left().value()); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Property"); + log.debug("get property failed with exception", e); + ResponseFormat responseFormat = + getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } + private Response deleteProperty(String componentId, String propertyId, HttpServletRequest request, String userId) { + ServletContext context = request.getSession().getServletContext(); + + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} modifier id is {}", url, userId); + + try { + + // delete the property + PropertyBusinessLogic businessLogic = getPropertyBL(context); + Either<Map.Entry<String, PropertyDefinition>, ResponseFormat> status = + businessLogic.deletePropertyFromComponent(componentId, propertyId, userId); + if (status.isRight()) { + log.debug("Failed to delete Property. Reason - ", status.right().value()); + return buildErrorResponse(status.right().value()); + } + Map.Entry<String, PropertyDefinition> property = status.left().value(); + String name = property.getKey(); + PropertyDefinition propertyDefinition = property.getValue(); + + log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId()); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT); + return buildOkResponse(responseFormat, propertyToJson(property)); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property"); + log.debug("delete property failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/PropertyServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/PropertyServlet.java deleted file mode 100644 index 12d788dd45..0000000000 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/PropertyServlet.java +++ /dev/null @@ -1,369 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.openecomp.sdc.be.servlets; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import com.jcabi.aspects.Loggable; -import fj.data.Either; -import io.swagger.annotations.*; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; -import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; -import org.openecomp.sdc.be.config.BeEcompErrorManager; -import org.openecomp.sdc.be.dao.api.ActionStatus; -import org.openecomp.sdc.be.impl.WebAppContextWrapper; -import org.openecomp.sdc.be.model.PropertyConstraint; -import org.openecomp.sdc.be.model.PropertyDefinition; -import org.openecomp.sdc.be.model.User; -import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser; -import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintSerialiser; -import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; -import org.openecomp.sdc.be.resources.data.EntryData; -import org.openecomp.sdc.common.api.Constants; -import org.openecomp.sdc.common.log.wrappers.Logger; -import org.openecomp.sdc.exception.ResponseFormat; -import org.springframework.web.context.WebApplicationContext; - -import javax.inject.Singleton; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) -@Path("/v1/catalog") -@Api(value = "Resource Property Servlet", description = "Resource Property Servlet") -@Singleton -public class PropertyServlet extends BeGenericServlet { - - private static final Logger log = Logger.getLogger(PropertyServlet.class.getName()); - - @POST - @Path("resources/{resourceId}/properties") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Create Resource Property", httpMethod = "POST", notes = "Returns created resource property", response = Response.class) - @ApiResponses(value = { @ApiResponse(code = 201, message = "Resource property created"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), - @ApiResponse(code = 409, message = "Resource property already exist") }) - public Response createProperty(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, @ApiParam(value = "Resource property to be created", required = true) String data, - @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { - - ServletContext context = request.getSession().getServletContext(); - - String url = request.getMethod() + " " + request.getRequestURI(); - log.debug("Start handle request of {} modifier id is {} data is {}", url, userId, data); - - try { - // convert json to PropertyDefinition - Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(resourceId, data); - if (either.isRight()) { - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value()); - return buildErrorResponse(responseFormat); - } - Map<String, PropertyDefinition> properties = either.left().value(); - if (properties == null || properties.size() != 1) { - log.info("Property conetnt is invalid - {}", data); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); - return buildErrorResponse(responseFormat); - } - Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next(); - String propertyName = entry.getKey(); - PropertyDefinition newPropertyDefinition = entry.getValue(); - - // create the new property - PropertyBusinessLogic businessLogic = getPropertyBL(context); - Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.createProperty(resourceId, propertyName, newPropertyDefinition, userId); - if (status.isRight()) { - log.info("Failed to create Property. Reason - ", status.right().value()); - return buildErrorResponse(status.right().value()); - } - EntryData<String, PropertyDefinition> property = status.left().value(); - String name = property.getKey(); - PropertyDefinition propertyDefinition = property.getValue(); - - log.debug("Property {} created successfully with id {}", name, propertyDefinition.getUniqueId()); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED); - return buildOkResponse(responseFormat, propertyToJson(property)); - - } catch (Exception e) { - BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Create Property"); - log.debug("create property failed with exception", e); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); - return buildErrorResponse(responseFormat); - - } - } - - @GET - @Path("resources/{resourceId}/properties/{propertyId}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Create Resource Property", httpMethod = "GET", notes = "Returns property of resource", response = Response.class) - @ApiResponses(value = { @ApiResponse(code = 200, message = "property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), - @ApiResponse(code = 404, message = "Resource property not found") }) - public Response getProperty(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId, @ApiParam(value = "proerty id to get", required = true) @PathParam("propertyId") final String propertyId, - @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { - - ServletContext context = request.getSession().getServletContext(); - - String url = request.getMethod() + " " + request.getRequestURI(); - log.debug("Start handle request of {}, modifier id is {}", url, userId); - - try { - - // - PropertyBusinessLogic businessLogic = getPropertyBL(context); - Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.getProperty(resourceId, propertyId, userId); - - if (status.isRight()) { - log.info("Failed to get Property. Reason - ", status.right().value()); - return buildErrorResponse(status.right().value()); - } - Entry<String, PropertyDefinition> property = status.left().value(); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); - return buildOkResponse(responseFormat, propertyToJson(property)); - } catch (Exception e) { - BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Property"); - log.debug("get property failed with exception", e); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); - return buildErrorResponse(responseFormat); - - } - } - - @DELETE - @Path("resources/{resourceId}/properties/{propertyId}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Create Resource Property", httpMethod = "DELETE", notes = "Returns deleted property", response = Response.class) - @ApiResponses(value = { @ApiResponse(code = 204, message = "deleted property"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), - @ApiResponse(code = 404, message = "Resource property not found") }) - public Response deleteProperty(@ApiParam(value = "resource id of property", required = true) @PathParam("resourceId") final String resourceId, - @ApiParam(value = "Property id to delete", required = true) @PathParam("propertyId") final String propertyId, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { - - ServletContext context = request.getSession().getServletContext(); - - String url = request.getMethod() + " " + request.getRequestURI(); - log.debug("Start handle request of {} modifier id is {}", url, userId); - - try { - - // delete the property - PropertyBusinessLogic businessLogic = getPropertyBL(context); - Either<Entry<String, PropertyDefinition>, ResponseFormat> status = businessLogic.deleteProperty(resourceId, propertyId, userId); - if (status.isRight()) { - log.debug("Failed to delete Property. Reason - ", status.right().value()); - return buildErrorResponse(status.right().value()); - } - Entry<String, PropertyDefinition> property = status.left().value(); - String name = property.getKey(); - PropertyDefinition propertyDefinition = property.getValue(); - - log.debug("Property {} deleted successfully with id {}", name, propertyDefinition.getUniqueId()); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT); - return buildOkResponse(responseFormat, propertyToJson(property)); - - } catch (Exception e) { - BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete Property"); - log.debug("delete property failed with exception", e); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); - return buildErrorResponse(responseFormat); - - } - } - - @PUT - @Path("resources/{resourceId}/properties/{propertyId}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Update Resource Property", httpMethod = "PUT", notes = "Returns updated property", response = Response.class) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Resource property updated"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content") }) - public Response updateProperty(@ApiParam(value = "resource id to update with new property", required = true) @PathParam("resourceId") final String resourceId, - @ApiParam(value = "proerty id to update", required = true) @PathParam("propertyId") final String propertyId, @ApiParam(value = "Resource property to update", required = true) String data, @Context final HttpServletRequest request, - @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { - - ServletContext context = request.getSession().getServletContext(); - - String url = request.getMethod() + " " + request.getRequestURI(); - log.debug("Start handle request of {}", url); - - // get modifier id - User modifier = new User(); - modifier.setUserId(userId); - log.debug("modifier id is {}", userId); - - try { - // convert json to PropertyDefinition - Either<Map<String, PropertyDefinition>, ActionStatus> either = getPropertyModel(resourceId, data); - if (either.isRight()) { - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(either.right().value()); - return buildErrorResponse(responseFormat); - } - Map<String, PropertyDefinition> properties = either.left().value(); - if (properties == null || properties.size() != 1) { - log.info("Property conetnt is invalid - {}", data); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); - return buildErrorResponse(responseFormat); - } - Entry<String, PropertyDefinition> entry = properties.entrySet().iterator().next(); - PropertyDefinition newPropertyDefinition = entry.getValue(); - - // update property - PropertyBusinessLogic businessLogic = getPropertyBL(context); - Either<EntryData<String, PropertyDefinition>, ResponseFormat> status = businessLogic.updateProperty(resourceId, propertyId, newPropertyDefinition, userId); - if (status.isRight()) { - log.info("Failed to update Property. Reason - ", status.right().value()); - return buildErrorResponse(status.right().value()); - } - EntryData<String, PropertyDefinition> property = status.left().value(); - PropertyDefinition propertyDefinition = property.getValue(); - - log.debug("Property id {} updated successfully ", propertyDefinition.getUniqueId()); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); - return buildOkResponse(responseFormat, propertyToJson(property)); - - } catch (Exception e) { - BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Update Property"); - log.debug("update property failed with exception", e); - ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); - return buildErrorResponse(responseFormat); - - } - } - - private Either<Map<String, PropertyDefinition>, ActionStatus> getPropertyModel(String resourceId, String data) { - JSONParser parser = new JSONParser(); - JSONObject root; - try { - Map<String, PropertyDefinition> properties = new HashMap<>(); - root = (JSONObject) parser.parse(data); - - Set entrySet = root.entrySet(); - Iterator iterator = entrySet.iterator(); - while (iterator.hasNext()) { - Entry next = (Entry) iterator.next(); - String propertyName = (String) next.getKey(); - JSONObject value = (JSONObject) next.getValue(); - String jsonString = value.toJSONString(); - Either<PropertyDefinition, ActionStatus> convertJsonToObject = convertJsonToObject(jsonString, PropertyDefinition.class); - if (convertJsonToObject.isRight()) { - return Either.right(convertJsonToObject.right().value()); - } - PropertyDefinition propertyDefinition = convertJsonToObject.left().value(); - String uniqueId = UniqueIdBuilder.buildPropertyUniqueId(resourceId, (String) propertyName); - propertyDefinition.setUniqueId(uniqueId); - properties.put(propertyName, propertyDefinition); - } - - return Either.left(properties); - } catch (ParseException e) { - log.info("Property conetnt is invalid - {}", data); - return Either.right(ActionStatus.INVALID_CONTENT); - } - } - - private String propertyToJson(Map.Entry<String, PropertyDefinition> property) { - JSONObject root = new JSONObject(); - String propertyName = property.getKey(); - PropertyDefinition propertyDefinition = property.getValue(); - JSONObject propertyDefinitionO = getPropertyDefinitionJSONObject(propertyDefinition); - root.put(propertyName, propertyDefinitionO); - propertyDefinition.getType(); - return root.toString(); - } - - private JSONObject getPropertyDefinitionJSONObject(PropertyDefinition propertyDefinition) { - - Either<String, ActionStatus> either = convertObjectToJson(propertyDefinition); - if (either.isRight()) { - return new JSONObject(); - } - String value = either.left().value(); - try { - return (JSONObject) new JSONParser().parse(value); - } catch (ParseException e) { - log.info("failed to convert input to json"); - log.debug("failed to convert to json", e); - return new JSONObject(); - } - - } - - private <T> Either<T, ActionStatus> convertJsonToObject(String data, Class<T> clazz) { - T t = null; - Type constraintType = new TypeToken<PropertyConstraint>() { - }.getType(); - Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create(); - try { - log.trace("convert json to object. json=\n {}", data); - t = gson.fromJson(data, clazz); - if (t == null) { - log.info("object is null after converting from json"); - return Either.right(ActionStatus.INVALID_CONTENT); - } - } catch (Exception e) { - // INVALID JSON - log.info("failed to convert from json"); - log.debug("failed to convert from json", e); - return Either.right(ActionStatus.INVALID_CONTENT); - } - return Either.left(t); - } - - private <T> Either<String, ActionStatus> convertObjectToJson(PropertyDefinition propertyDefinition) { - Type constraintType = new TypeToken<PropertyConstraint>() { - }.getType(); - Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintSerialiser()).create(); - try { - log.trace("convert object to json. propertyDefinition= {}", propertyDefinition); - String json = gson.toJson(propertyDefinition); - if (json == null) { - log.info("object is null after converting to json"); - return Either.right(ActionStatus.INVALID_CONTENT); - } - return Either.left(json); - } catch (Exception e) { - // INVALID JSON - log.info("failed to convert to json"); - log.debug("failed to convert fto json", e); - return Either.right(ActionStatus.INVALID_CONTENT); - } - - } - - private PropertyBusinessLogic getPropertyBL(ServletContext context) { - WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); - WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); - return webApplicationContext.getBean(PropertyBusinessLogic.class); - } - -} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java index ddb405779d..00b04a4ffc 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java @@ -105,12 +105,6 @@ public class TypesFetchServlet extends AbstractValidationsServlet { } } - private PropertyBusinessLogic getPropertyBL(ServletContext context) { - WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR); - WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context); - return webApplicationContext.getBean(PropertyBusinessLogic.class); - } - @GET @Path("interfaceLifecycleTypes") @Consumes(MediaType.APPLICATION_JSON) diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java index 6a06c943a0..04119fed7b 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java @@ -488,7 +488,7 @@ public class CapabilityRequirementConverter { if (isNotEmpty(properties)) { Map<String, ToscaProperty> toscaProperties = new HashMap<>(); for (PropertyDefinition property : properties) { - ToscaProperty toscaProperty = PropertyConvertor.getInstance().convertProperty(dataTypes, property, true); + ToscaProperty toscaProperty = PropertyConvertor.getInstance().convertProperty(dataTypes, property, PropertyConvertor.PropertyType.CAPABILITY); toscaProperties.put(property.getName(), toscaProperty); } toscaCapability.setProperties(toscaProperties); @@ -520,7 +520,7 @@ public class CapabilityRequirementConverter { if (isNotEmpty(properties)) { Map<String, ToscaProperty> toscaProperties = new HashMap<>(); for (PropertyDefinition property : properties) { - ToscaProperty toscaProperty = PropertyConvertor.getInstance().convertProperty(dataTypes, property, true); + ToscaProperty toscaProperty = PropertyConvertor.getInstance().convertProperty(dataTypes, property, PropertyConvertor.PropertyType.CAPABILITY); toscaProperties.put(property.getName(), toscaProperty); } toscaCapability.setProperties(toscaProperties); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java index d128d5349f..04c7c69daa 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java @@ -20,11 +20,13 @@ package org.openecomp.sdc.be.tosca; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; -import fj.data.Either; +import java.io.StringReader; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + import org.apache.commons.lang3.StringUtils; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; @@ -35,6 +37,7 @@ import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.converters.DataTypePropertyConverter; import org.openecomp.sdc.be.model.tosca.converters.ToscaMapValueConverter; +import org.openecomp.sdc.be.model.tosca.converters.ToscaStringConvertor; import org.openecomp.sdc.be.model.tosca.converters.ToscaValueBaseConverter; import org.openecomp.sdc.be.model.tosca.converters.ToscaValueConverter; import org.openecomp.sdc.be.tosca.model.EntrySchema; @@ -42,18 +45,24 @@ import org.openecomp.sdc.be.tosca.model.ToscaNodeType; import org.openecomp.sdc.be.tosca.model.ToscaProperty; import org.openecomp.sdc.common.log.wrappers.Logger; -import java.io.StringReader; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; + +import fj.data.Either; public class PropertyConvertor { private static PropertyConvertor instance; private JsonParser jsonParser = new JsonParser(); private static final Logger log = Logger.getLogger(PropertyConvertor.class); + public enum PropertyType { + CAPABILITY, + INPUT, + PROPERTY + } Gson gson = new Gson(); - protected PropertyConvertor() { + public PropertyConvertor() { } @@ -74,7 +83,7 @@ public class PropertyConvertor { // take only the properties of this resource props.stream().filter(p -> p.getOwnerId() == null || p.getOwnerId().equals(component.getUniqueId())).forEach(property -> { - properties.put(property.getName(), convertProperty(dataTypes, property, false)); + properties.put(property.getName(), convertProperty(dataTypes, property, PropertyType.PROPERTY)); }); if (!properties.isEmpty()) { toscaNodeType.setProperties(properties); @@ -84,7 +93,7 @@ public class PropertyConvertor { return Either.left(toscaNodeType); } - public ToscaProperty convertProperty(Map<String, DataTypeDefinition> dataTypes, PropertyDataDefinition property, boolean isCapabiltyProperty) { + public ToscaProperty convertProperty(Map<String, DataTypeDefinition> dataTypes, PropertyDefinition property, PropertyType propertyType) { ToscaProperty prop = new ToscaProperty(); String innerType = null; @@ -96,22 +105,35 @@ public class PropertyConvertor { eschema.setDescription(schema.getProperty().getDescription()); prop.setEntry_schema(eschema); } - return getToscaProperty(dataTypes, property, isCapabiltyProperty, prop, innerType); + return getToscaProperty(dataTypes, property, prop, innerType, propertyType); } - private ToscaProperty getToscaProperty(Map<String, DataTypeDefinition> dataTypes, PropertyDataDefinition property, boolean isCapabiltyProperty, ToscaProperty prop, String innerType) { + private ToscaProperty getToscaProperty(Map<String, DataTypeDefinition> dataTypes, + PropertyDataDefinition property, + ToscaProperty prop, + String innerType, + PropertyType propertyType) { log.trace("try to convert property {} from type {} with default value [{}]", property.getName(), property.getType(), property.getDefaultValue()); - Object convertedObj = convertToToscaObject(property.getType(), property.getDefaultValue(), innerType, dataTypes, false); + String defaultValue = property.getDefaultValue(); + if(Objects.isNull(defaultValue)) { + defaultValue = property.getValue(); + } + Object convertedObj = + convertToToscaObject(property.getType(), defaultValue, innerType, dataTypes, false); if (convertedObj != null) { prop.setDefaultp(convertedObj); } prop.setType(property.getType()); prop.setDescription(property.getDescription()); - if (isCapabiltyProperty) { - prop.setStatus(property.getStatus()); - } prop.setRequired(property.isRequired()); + switch (propertyType) { + case CAPABILITY: + prop.setStatus(property.getStatus()); + break; + default: + break; + } return prop; } @@ -198,9 +220,9 @@ public class PropertyConvertor { } private boolean valueStartsWithNonJsonChar(String value) { - return value.startsWith("/") || value.startsWith(":") || value.startsWith("#"); + return value.startsWith("/") || value.startsWith(":"); } - + public void convertAndAddValue(Map<String, DataTypeDefinition> dataTypes, Map<String, Object> props, PropertyDataDefinition prop, Supplier<String> supplier) { Object convertedValue = convertValue(dataTypes, prop, supplier); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java index d0286d72d9..ecead12478 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -20,10 +20,11 @@ package org.openecomp.sdc.be.tosca; -import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.addInterfaceDefinitionElement; -import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.addInterfaceTypeElement; - +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutableTriple; @@ -32,48 +33,24 @@ import org.openecomp.sdc.be.components.impl.exceptions.SdcResourceNotFoundExcept import org.openecomp.sdc.be.config.ConfigurationManager; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; -import org.openecomp.sdc.be.model.ArtifactDefinition; -import org.openecomp.sdc.be.model.CapabilityDefinition; -import org.openecomp.sdc.be.model.Component; -import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceInput; -import org.openecomp.sdc.be.model.ComponentInstanceProperty; -import org.openecomp.sdc.be.model.ComponentParametersView; -import org.openecomp.sdc.be.model.DataTypeDefinition; -import org.openecomp.sdc.be.model.GroupInstance; -import org.openecomp.sdc.be.model.InputDefinition; -import org.openecomp.sdc.be.model.InterfaceDefinition; -import org.openecomp.sdc.be.model.PropertyDefinition; -import org.openecomp.sdc.be.model.RelationshipInfo; -import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; -import org.openecomp.sdc.be.model.RequirementDefinition; -import org.openecomp.sdc.be.model.Resource; -import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.*; import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter; -import org.openecomp.sdc.be.model.operations.api.IInterfaceLifecycleOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; -import org.openecomp.sdc.be.tosca.model.SubstitutionMapping; -import org.openecomp.sdc.be.tosca.model.ToscaCapability; -import org.openecomp.sdc.be.tosca.model.ToscaGroupTemplate; -import org.openecomp.sdc.be.tosca.model.ToscaMetadata; -import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate; -import org.openecomp.sdc.be.tosca.model.ToscaNodeType; -import org.openecomp.sdc.be.tosca.model.ToscaPolicyTemplate; -import org.openecomp.sdc.be.tosca.model.ToscaProperty; -import org.openecomp.sdc.be.tosca.model.ToscaTemplate; -import org.openecomp.sdc.be.tosca.model.ToscaTemplateRequirement; -import org.openecomp.sdc.be.tosca.model.ToscaTopolgyTemplate; +import org.openecomp.sdc.be.model.tosca.converters.ToscaValueBaseConverter; +import org.openecomp.sdc.be.tosca.model.*; import org.openecomp.sdc.be.tosca.utils.ForwardingPathToscaUtil; import org.openecomp.sdc.be.tosca.utils.InputConverter; +import org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil; import org.openecomp.sdc.common.log.wrappers.Logger; -import org.openecomp.sdc.exception.ResponseFormat; +import org.openecomp.sdc.externalupload.utils.ServiceUtils; import org.springframework.beans.factory.annotation.Autowired; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions.FlowStyle; @@ -89,15 +66,8 @@ import org.yaml.snakeyaml.representer.Represent; import org.yaml.snakeyaml.representer.Representer; import java.beans.IntrospectionException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -105,6 +75,8 @@ import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.collections.MapUtils.isNotEmpty; import static org.apache.commons.lang.StringUtils.isNotEmpty; +import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.addInterfaceDefinitionElement; +import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.addInterfaceTypeElement; @org.springframework.stereotype.Component("tosca-export-handler") public class ToscaExportHandler { @@ -145,6 +117,8 @@ public class ToscaExportHandler { private static final List<Map<String, Map<String, String>>> DEFAULT_IMPORTS = ConfigurationManager .getConfigurationManager().getConfiguration().getDefaultImports(); + public ToscaExportHandler(){} + public Either<ToscaRepresentation, ToscaError> exportComponent(Component component) { Either<ToscaTemplate, ToscaError> toscaTemplateRes = convertToToscaTemplate(component); @@ -274,12 +248,16 @@ public class ToscaExportHandler { } List<ComponentInstance> componentInstances = component.getComponentInstances(); - Map<String, List<ComponentInstanceProperty>> componentInstancesProperties = component - .getComponentInstancesProperties(); + Map<String, List<ComponentInstanceProperty>> componentInstancesProperties = + component.getComponentInstancesProperties(); + Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces = + component.getComponentInstancesInterfaces(); if (componentInstances != null && !componentInstances.isEmpty()) { - Either<Map<String, ToscaNodeTemplate>, ToscaError> nodeTemplates = convertNodeTemplates(component, - componentInstances, componentInstancesProperties, componentCache, dataTypes, topologyTemplate); + Either<Map<String, ToscaNodeTemplate>, ToscaError> nodeTemplates = + convertNodeTemplates(component, componentInstances, + componentInstancesProperties, componentInstanceInterfaces, + componentCache, dataTypes, topologyTemplate); if (nodeTemplates.isRight()) { return Either.right(nodeTemplates.right().value()); } @@ -335,7 +313,27 @@ public class ToscaExportHandler { return Either.left(toscaNode); } - private void addGroupsToTopologyTemplate(Component component, ToscaTopolgyTemplate topologyTemplate) { + private Either<ToscaTopolgyTemplate, ToscaError> fillInputs(Component component, + ToscaTopolgyTemplate topologyTemplate, Map<String, DataTypeDefinition> dataTypes) { + if (log.isDebugEnabled()) { + log.debug("fillInputs for component {}", component.getUniqueId()); + } + List<InputDefinition> inputDef = component.getInputs(); + Map<String, ToscaProperty> inputs = new HashMap<>(); + + if (inputDef != null) { + inputDef.forEach(i -> { + ToscaProperty property = propertyConvertor.convertProperty(dataTypes, i, PropertyConvertor.PropertyType.INPUT); + inputs.put(i.getName(), property); + }); + if (!inputs.isEmpty()) { + topologyTemplate.setInputs(inputs); + } + } + return Either.left(topologyTemplate); + } + + private void addGroupsToTopologyTemplate(Component component, ToscaTopolgyTemplate topologyTemplate) { Map<String, ToscaGroupTemplate> groups = groupExportParser.getGroups(component); @@ -436,8 +434,6 @@ public class ToscaExportHandler { Map<String, Component> componentCache = new HashMap<>(); if (!ModelConverter.isAtomicComponent(component)) { - List<ComponentInstance> componentInstances = component.getComponentInstances(); - List<Map<String, Map<String, String>>> additionalImports = toscaTemplate.getImports() == null ? new ArrayList<>(DEFAULT_IMPORTS) : new ArrayList<>(toscaTemplate.getImports()); @@ -457,6 +453,7 @@ public class ToscaExportHandler { additionalImports.add(importsListMember); } } + List<ComponentInstance> componentInstances = component.getComponentInstances(); if (componentInstances != null && !componentInstances.isEmpty()) { componentInstances.forEach(ci -> createDependency(componentCache, additionalImports, dependecies, ci)); } @@ -582,20 +579,35 @@ public class ToscaExportHandler { Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value(); List<InputDefinition> inputDef = component.getInputs(); - Map<String, ToscaProperty> inputs = new HashMap<>(); - addInterfaceDefinitionElement(component, toscaNodeType, isAssociatedResourceComponent); + Map<String, ToscaProperty> mergedProperties = new HashMap<>(); + addInterfaceDefinitionElement(component, toscaNodeType, dataTypes, isAssociatedResourceComponent); if (inputDef != null) { - inputDef.forEach(i -> { - ToscaProperty property = propertyConvertor.convertProperty(dataTypes, i, false); - inputs.put(i.getName(), property); - }); - if (!inputs.isEmpty()) { - toscaNodeType.setProperties(inputs); - } + addInputsToProperties(dataTypes, inputDef, mergedProperties); + } + + if(CollectionUtils.isNotEmpty(component.getProperties())) { + List<PropertyDefinition> properties = component.getProperties(); + mergedProperties = properties.stream().collect(Collectors.toMap( + PropertyDataDefinition::getName, + property -> propertyConvertor.convertProperty(dataTypes, property, PropertyConvertor.PropertyType.PROPERTY))); } + if (!mergedProperties.isEmpty()) { + toscaNodeType.setProperties(mergedProperties); + } + // Extracted to method for code reuse return convertReqCapAndTypeName(componentsCache, component, toscaNode, nodeTypes, toscaNodeType, dataTypes); } + private void addInputsToProperties(Map<String, DataTypeDefinition> dataTypes, + List<InputDefinition> inputDef, + Map<String, ToscaProperty> mergedProperties) { + for(InputDefinition input : inputDef) { + ToscaProperty property = propertyConvertor.convertProperty(dataTypes, input, PropertyConvertor.PropertyType.INPUT); + mergedProperties.put(input.getName(), property); + } + } + + private Either<ToscaTemplate, ToscaError> convertReqCapAndTypeName(Map<String, Component> componentsCache, Component component, ToscaTemplate toscaNode, Map<String, ToscaNodeType> nodeTypes, ToscaNodeType toscaNodeType, Map<String, DataTypeDefinition> dataTypes) { @@ -635,9 +647,11 @@ public class ToscaExportHandler { return Either.left(toscaNode); } - private Either<Map<String, ToscaNodeTemplate>, ToscaError> convertNodeTemplates(Component component, + protected Either<Map<String, ToscaNodeTemplate>, ToscaError> convertNodeTemplates( + Component component, List<ComponentInstance> componentInstances, Map<String, List<ComponentInstanceProperty>> componentInstancesProperties, + Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces, Map<String, Component> componentCache, Map<String, DataTypeDefinition> dataTypes, ToscaTopolgyTemplate topologyTemplate) { @@ -704,7 +718,11 @@ public class ToscaExportHandler { addComponentInstanceInputs(dataTypes, componentInstancesInputs, instanceUniqueId, props); } - if (!props.isEmpty()) { + //M3[00001] - NODE TEMPLATE INTERFACES - START + handleInstanceInterfaces(componentInstanceInterfaces, componentInstance, dataTypes, nodeTemplate, + instanceUniqueId, component); + //M3[00001] - NODE TEMPLATE INTERFACES - END + if (props != null && !props.isEmpty()) { nodeTemplate.setProperties(props); } @@ -749,6 +767,70 @@ public class ToscaExportHandler { return convertNodeTemplatesRes; } + private void handleInstanceInterfaces( + Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces, + ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, ToscaNodeTemplate nodeTemplate, + String instanceUniqueId, + Component parentComponent) { + + Map<String, Object> interfaces; + + // we need to handle service proxy interfaces + if(isComponentOfTypeServiceProxy(componentInstance)) { + if(MapUtils.isEmpty(componentInstanceInterfaces) + || !componentInstanceInterfaces.containsKey(instanceUniqueId)) { + interfaces = null; + } else { + List<ComponentInstanceInterface> currServiceInterfaces = + componentInstanceInterfaces.get(instanceUniqueId); + + Map<String, InterfaceDefinition> tmpInterfaces = new HashMap<>(); + currServiceInterfaces.forEach(instInterface -> tmpInterfaces.put(instInterface + .getUniqueId(), instInterface)); + + interfaces = InterfacesOperationsToscaUtil + .getInterfacesMap(parentComponent, tmpInterfaces, dataTypes, true, true); + } + } else { + interfaces = + getComponentInstanceInterfaceInstances(componentInstanceInterfaces, + componentInstance, instanceUniqueId); + } + nodeTemplate.setInterfaces(interfaces); + } + + private boolean isComponentOfTypeServiceProxy(ComponentInstance componentInstance) { + return Objects.nonNull(componentInstance.getOriginType()) + && componentInstance.getOriginType().getValue().equals("Service Proxy"); + } + + //M3[00001] - NODE TEMPLATE INTERFACES - START + private Map<String, Object> getComponentInstanceInterfaceInstances(Map<String, List<ComponentInstanceInterface>> componentInstancesInterfaces, + ComponentInstance componentInstance, + String instanceUniqueId) { + if(MapUtils.isEmpty(componentInstancesInterfaces)) { + return null; + } + + List<ComponentInstanceInterface> componentInstanceInterfaces = + componentInstancesInterfaces.get(instanceUniqueId); + + if(CollectionUtils.isEmpty(componentInstanceInterfaces)) { + return null; + } + + Map<String, Object> interfaces = new HashMap<>(); + for(ComponentInstanceInterface componentInstanceInterface : componentInstanceInterfaces) { + interfaces.put(componentInstanceInterface.getInterfaceId(), + removeOperationsKeyFromInterface(componentInstanceInterface.getInterfaceInstanceDataDefinition())); + } + + componentInstance.setInterfaces(interfaces); + + return interfaces; + } + //M3[00001] - NODE TEMPLATE INTERFACES - END + private void addComponentInstanceInputs(Map<String, DataTypeDefinition> dataTypes, Map<String, List<ComponentInstanceInput>> componentInstancesInputs, String instanceUniqueId, Map<String, Object> props) { @@ -791,6 +873,34 @@ public class ToscaExportHandler { } } + /** + * @param dataTypes + * @param componentInstance + * @param props + * @param prop + * @param supplier + */ + private void convertAndAddValue(Map<String, DataTypeDefinition> dataTypes, ComponentInstance componentInstance, + Map<String, Object> props, PropertyDefinition prop, Supplier<String> supplier) { + Object convertedValue = convertValue(dataTypes, componentInstance, prop, supplier); + if (!ToscaValueBaseConverter.isEmptyObjectValue(convertedValue)) { + props.put(prop.getName(), convertedValue); + } + } + + private <T extends PropertyDefinition> Object convertValue(Map<String, DataTypeDefinition> dataTypes, + ComponentInstance componentInstance, T input, Supplier<String> supplier) { + log.debug("Convert property or input value {} for instance {}", input.getName(), + componentInstance.getUniqueId()); + String propertyType = input.getType(); + String innerType = null; + if (input.getSchema() != null && input.getSchema().getProperty() != null) { + innerType = input.getSchema().getProperty().getType(); + } + return propertyConvertor.convertToToscaObject(propertyType, supplier.get(), innerType, + dataTypes, true); + } + private ToscaNodeType createNodeType(Component component) { ToscaNodeType toscaNodeType = new ToscaNodeType(); if (ModelConverter.isAtomicComponent(component)) { @@ -1128,5 +1238,22 @@ public class ToscaExportHandler { } } + private Object removeOperationsKeyFromInterface(Object interfaceInstanceDataDefinition) { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false); + + Map<String, Object> interfaceAsMap = ServiceUtils.getObjectAsMap(interfaceInstanceDataDefinition); + Map<String, Object> operations = (Map<String, Object>) interfaceAsMap.remove("operations"); + interfaceAsMap.remove("empty"); + + if(MapUtils.isNotEmpty(operations)) { + interfaceAsMap.putAll(operations); + } + + Object interfaceObject = objectMapper.convertValue(interfaceAsMap, Object.class); + + return interfaceObject; + + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java index c27944e8ee..b67a2cf233 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java @@ -20,6 +20,9 @@ package org.openecomp.sdc.be.tosca.model; +import org.apache.commons.collections.MapUtils; + +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,6 +33,7 @@ public class ToscaNodeTemplate { private Map<String, Object> properties; private List<Map<String, ToscaTemplateRequirement>> requirements; private Map<String, ToscaTemplateCapability> capabilities; + private Map<String, Object> interfaces; public String getType() { return type; @@ -78,4 +82,17 @@ public class ToscaNodeTemplate { public void setDescription(String description) { this.description = description; } + + public void setInterfaces( + Map<String, Object> interfaces) { + this.interfaces = interfaces; + } + + public void addInterface(String interfaceName, Object interfaceDataDefinition) { + if (MapUtils.isEmpty(this.interfaces)) { + this.interfaces = new HashMap<>(); + } + + this.interfaces.put(interfaceName, interfaceDataDefinition); + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InputConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InputConverter.java index f6619b9aaa..c7e4d9b635 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InputConverter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InputConverter.java @@ -42,7 +42,8 @@ public class InputConverter { if (inputDef != null) { inputDef.forEach(i -> { //Extract input the same as property - ToscaProperty toscaProperty = propertyConvertor.convertProperty(dataTypes, i, false); + ToscaProperty toscaProperty = propertyConvertor.convertProperty(dataTypes, i, + PropertyConvertor.PropertyType.INPUT); //now that we have Tosca property we create new object called tosca input which drives from it ToscaInput toscaInput = new ToscaInput(toscaProperty); List<Annotation> annotations = i.getAnnotations(); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java index 106aa58133..a72f57d61c 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfacesOperationsToscaUtil.java @@ -30,6 +30,7 @@ import org.apache.commons.collections.MapUtils; import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.Product; import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition; @@ -103,6 +104,7 @@ public class InterfacesOperationsToscaUtil { * @param nodeType to which the interfaces element will be added */ public static void addInterfaceDefinitionElement(Component component, ToscaNodeType nodeType, + Map<String, DataTypeDefinition> dataTypes, boolean isAssociatedResourceComponent) { if (component instanceof Product) { return; @@ -111,6 +113,28 @@ public class InterfacesOperationsToscaUtil { if (MapUtils.isEmpty(interfaces)) { return; } + Map<String, Object> toscaInterfaceDefinitions = getInterfacesMap(component, dataTypes, + isAssociatedResourceComponent); + if (MapUtils.isNotEmpty(toscaInterfaceDefinitions)) { + nodeType.setInterfaces(toscaInterfaceDefinitions); + } + } + + private static Map<String, Object> getInterfacesMap(Component component, + Map<String, DataTypeDefinition> dataTypes, + boolean isAssociatedResourceComponent) { + return getInterfacesMap(component, component.getInterfaces(), dataTypes, isAssociatedResourceComponent, false); + } + + public static Map<String, Object> getInterfacesMap(Component component, + Map<String, InterfaceDefinition> interfaces, + Map<String, DataTypeDefinition> dataTypes, + boolean isAssociatedResourceComponent, + boolean isServiceProxyInterface) { + if(MapUtils.isEmpty(interfaces)) { + return null; + } + Map<String, Object> toscaInterfaceDefinitions = new HashMap<>(); for (InterfaceDefinition interfaceDefinition : interfaces.values()) { ToscaInterfaceDefinition toscaInterfaceDefinition = new ToscaInterfaceDefinition(); @@ -137,13 +161,46 @@ public class InterfacesOperationsToscaUtil { toscaInterfaceDefinition.setOperations(toscaOperations); Map<String, Object> interfaceDefAsMap = getObjectAsMap(toscaInterfaceDefinition); Map<String, Object> operationsMap = (Map<String, Object>) interfaceDefAsMap.remove(OPERATIONS_KEY); - handleDefaults(operationsMap); + if (isServiceProxyInterface) { + handleServiceProxyOperationInputValue(operationsMap, interfaceType); + } else { + handleDefaults(operationsMap); + } interfaceDefAsMap.putAll(operationsMap); toscaInterfaceDefinitions.put(getLastPartOfName(interfaceType), interfaceDefAsMap); } - if (MapUtils.isNotEmpty(toscaInterfaceDefinitions)) { - nodeType.setInterfaces(toscaInterfaceDefinitions); + + return toscaInterfaceDefinitions; + } + + private static void handleServiceProxyOperationInputValue(Map<String, Object> operationsMap, String parentKey) { + for (Map.Entry<String, Object> operationEntry : operationsMap.entrySet()) { + final Object value = operationEntry.getValue(); + final String key = operationEntry.getKey(); + if (value instanceof Map) { + if ("inputs".equals(parentKey)) { + Object defaultValue = getDefaultValue((Map<String, Object>) value); + operationsMap.put(key, defaultValue); + } else { + handleServiceProxyOperationInputValue((Map<String, Object>) value, key); + } + } + } + } + + private static Object getDefaultValue(Map<String, Object> inputValueMap) { + Object defaultValue = null; + for (Map.Entry<String, Object> operationEntry : inputValueMap.entrySet()) { + final Object value = operationEntry.getValue(); + if (value instanceof Map) { + getDefaultValue((Map<String, Object>) value); + } + final String key = operationEntry.getKey(); + if (key.equals(DEFAULTP)) { + defaultValue = inputValueMap.remove(key); + } } + return defaultValue; } /* diff --git a/catalog-be/src/main/java/org/openecomp/sdc/externalupload/utils/ServiceUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/externalupload/utils/ServiceUtils.java new file mode 100644 index 0000000000..ba6f9c233c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/externalupload/utils/ServiceUtils.java @@ -0,0 +1,89 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.externalupload.utils; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.beanutils.BeanUtils; + +import java.lang.reflect.Field; +import java.util.*; + +public class ServiceUtils { + private static final char[] CHARS = new char[]{ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + private static final String TYPE = "type"; + private static final String NODE = "node"; + + public static <T> Optional<T> createObjectUsingSetters(Object objectCandidate, + Class<T> classToCreate) + throws Exception { + if (Objects.isNull(objectCandidate)) { + return Optional.empty(); + } + + Map<String, Object> objectAsMap = getObjectAsMap(objectCandidate); + T result = classToCreate.newInstance(); + + List<Field> declaredFields = getAllFields(classToCreate); + for( Field field : declaredFields){ + if(isComplexClass(field)){ + Optional<?> objectUsingSetters = + createObjectUsingSetters(objectAsMap.get(field.getName()), field.getType()); + if( objectUsingSetters.isPresent()){ + objectAsMap.remove(field.getName()); + objectAsMap.put(field.getName(), objectUsingSetters.get()); + } + } + } + BeanUtils.populate(result, objectAsMap); + + return Optional.of(result); + } + + private static <T> List<Field> getAllFields(Class<T> clazz) { + List<Field> fields = new ArrayList<>(); + for(Class<?> c = clazz; c != null; c = c.getSuperclass()) { + fields.addAll(Arrays.asList(c.getDeclaredFields())); + } + + return fields; + } + + private static boolean isComplexClass(Field field) { + return !field.getType().equals(Map.class) + && !field.getType().equals(String.class) + && !field.getType().equals(Integer.class) + && !field.getType().equals(Float.class) + && !field.getType().equals(Double.class) + && !field.getType().equals(Set.class) + && !field.getType().equals(Object.class) + && !field.getType().equals(List.class); + } + public static Map<String, Object> getObjectAsMap(Object obj) { + return new ObjectMapper().convertValue(obj, Map.class); + } + + public static Set<String> getClassFieldNames(Class<? extends Object> classType) { + Set<String> fieldNames = new HashSet<>(); + List<Field> allFields = getAllFields(classType); + allFields.forEach(field -> fieldNames.add(field.getName())); + + return fieldNames; + } +}
\ No newline at end of file |