* limitations under the License.
* ============LICENSE_END=========================================================
*/
+
package org.openecomp.sdc.be.components.impl;
import static org.openecomp.sdc.be.components.attribute.GetOutputUtils.isGetOutputValueForOutput;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.text.StringEscapeUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
import org.onap.sdc.tosca.datatypes.model.PropertyType;
import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
-import org.openecomp.sdc.be.components.impl.exceptions.ToscaFunctionExceptionSupplier;
import org.openecomp.sdc.be.components.impl.exceptions.ToscaGetFunctionExceptionSupplier;
import org.openecomp.sdc.be.components.impl.instance.ComponentInstanceChangeOperationOrchestrator;
import org.openecomp.sdc.be.components.impl.utils.DirectivesUtil;
import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
+import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
import org.openecomp.sdc.be.model.LifecycleStateEnum;
import org.openecomp.sdc.be.model.OutputDefinition;
import org.openecomp.sdc.be.model.PolicyDefinition;
+import org.openecomp.sdc.be.model.PropertyConstraint;
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.operations.impl.UniqueIdBuilder;
import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
+import org.openecomp.sdc.be.model.validation.ToscaFunctionValidator;
import org.openecomp.sdc.be.resources.data.ComponentInstanceData;
import org.openecomp.sdc.be.user.Role;
import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
import org.openecomp.sdc.common.util.ValidationUtils;
import org.openecomp.sdc.exception.ResponseFormat;
import org.springframework.beans.factory.annotation.Autowired;
+import org.yaml.snakeyaml.Yaml;
@org.springframework.stereotype.Component
public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
private static final String CREATE_OR_UPDATE_PROPERTY_VALUE = "CreateOrUpdatePropertyValue";
private static final String FAILED_TO_COPY_COMP_INSTANCE_TO_CANVAS = "Failed to copy the component instance to the canvas";
private static final String COPY_COMPONENT_INSTANCE_OK = "Copy component instance OK";
- private static final String CANNOT_ATTACH_RESOURCE_INSTANCES_TO_CONTAINER_RESOURCE_OF_TYPE = "Cannot attach resource instances to container resource of type {}";
+ private static final String CANNOT_ATTACH_RESOURCE_INSTANCES_TO_CONTAINER_RESOURCE_OF_TYPE =
+ "Cannot attach resource instances to container resource of type {}";
private static final String FAILED_TO_UPDATE_COMPONENT_INSTANCE_CAPABILITY = "Failed to update component instance capability on instance {} in "
+ "container {}";
private static final String SERVICE_PROXY = "serviceProxy";
private final ComponentInstanceChangeOperationOrchestrator onChangeInstanceOperationOrchestrator;
private final ForwardingPathOperation forwardingPathOperation;
private final NodeFilterOperation nodeFilterOperation;
+ private final ToscaFunctionValidator toscaFunctionValidator;
+ private final PropertyBusinessLogic propertyBusinessLogic;
@Autowired
private CompositionBusinessLogic compositionBusinessLogic;
@Autowired
ComponentInstanceMergeDataBusinessLogic compInstMergeDataBL,
ComponentInstanceChangeOperationOrchestrator onChangeInstanceOperationOrchestrator,
ForwardingPathOperation forwardingPathOperation, NodeFilterOperation nodeFilterOperation,
- ArtifactsOperations artifactToscaOperation) {
+ ArtifactsOperations artifactToscaOperation, final ToscaFunctionValidator toscaFunctionValidator,
+ PropertyBusinessLogic propertyBusinessLogic) {
super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
artifactToscaOperation);
this.componentInstanceOperation = componentInstanceOperation;
this.onChangeInstanceOperationOrchestrator = onChangeInstanceOperationOrchestrator;
this.forwardingPathOperation = forwardingPathOperation;
this.nodeFilterOperation = nodeFilterOperation;
+ this.toscaFunctionValidator = toscaFunctionValidator;
+ this.propertyBusinessLogic = propertyBusinessLogic;
}
public ComponentInstance createComponentInstance(String containerComponentParam, String containerComponentId, String userId,
}
if (CollectionUtils.isNotEmpty(filteredGroups)) {
filteredGroups.stream()
- .filter(g -> g.getArtifacts() != null && g.getArtifacts().stream().anyMatch(p -> p.equals(artifactDefinition.getGeneratedFromId()))).findFirst()
+ .filter(g -> g.getArtifacts() != null &&
+ g.getArtifacts().stream().anyMatch(p -> p.equals(artifactDefinition.getGeneratedFromId()))).findFirst()
.ifPresent(g -> fillInstanceArtifactMap(groupInstancesArtifacts, artifactDefinition, g));
}
}
}
ComponentInstance foundResourceInstance = resourceInstanceStatus.left().value();
+ // Validate instance property against it's constrains
+ Either<Boolean, ResponseFormat> constraintValidatorResponse = validatePropertyValueConstraint(properties, componentId);
+ if (constraintValidatorResponse.isRight()) {
+ log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
+ return Either.right(constraintValidatorResponse.right().value());
+ }
// lock resource
StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType());
if (lockStatus != StorageOperationStatus.OK) {
for (ComponentInstanceProperty property : properties) {
validateMandatoryFields(property);
validatePropertyExistsOnComponent(property, containerComponent, foundResourceInstance);
+ validatePropertyConstraintsNotChanged(properties, foundResourceInstance);
String propertyParentUniqueId = property.getParentUniqueId();
if (property.isToscaFunction()) {
- if (property.getToscaFunction().getType() == null) {
- throw ToscaFunctionExceptionSupplier.missingFunctionType().get();
+ toscaFunctionValidator.validate(property, containerComponent);
+ property.setValue(StringEscapeUtils.unescapeJava(property.getToscaFunction().getValue()));
+ if (ToscaFunctionType.GET_INPUT == property.getToscaFunction().getType()) {
+ property.setGetInputValues(Collections.singletonList(buildGetInputValue(property)));
}
- if (property.isToscaGetFunction()) {
- validateToscaGetFunction(property, containerComponent);
+ }
+ if (CollectionUtils.isNotEmpty(property.getSubPropertyToscaFunctions())) {
+ ToscaPropertyType type = ToscaPropertyType.isValidType(property.getType());
+ if (ToscaPropertyType.LIST.equals(type)) {
+ final JSONArray jsonArray = property.getValue() == null ? new JSONArray() : new JSONArray(property.getValue());
+ property.getSubPropertyToscaFunctions().stream().forEach(subToscaFunction -> {
+ addE(jsonArray, subToscaFunction.getSubPropertyPath(), subToscaFunction.getToscaFunction().getValue());
+ });
+ property.setValue(jsonArray.toString());
+ } else {
+ final JSONObject jObject = property.getValue() == null ? new JSONObject() : new JSONObject(property.getValue());
+ property.getSubPropertyToscaFunctions().stream().forEach(subToscaFunction -> {
+ addE(jObject, subToscaFunction.getSubPropertyPath(), subToscaFunction.getToscaFunction().getValue());
+ });
+ property.setValue(jObject.toString());
}
- property.setValue(property.getToscaFunction().getValue());
}
Either<String, ResponseFormat> updatedPropertyValue = updatePropertyObjectValue(property, containerComponent.getModel());
if (updatedPropertyValue.isRight()) {
}
}
+ private GetInputValueDataDefinition buildGetInputValue(final ComponentInstanceProperty property) {
+ final GetInputValueDataDefinition getInputValueDataDefinition = new GetInputValueDataDefinition();
+ getInputValueDataDefinition.setPropName(property.getName());
+ getInputValueDataDefinition.setInputName(((ToscaGetFunctionDataDefinition) property.getToscaFunction()).getPropertyName());
+ getInputValueDataDefinition.setInputId(((ToscaGetFunctionDataDefinition) property.getToscaFunction()).getPropertyUniqueId());
+ return getInputValueDataDefinition;
+ }
+
+ private void addE(JSONArray jsonArray, List<String> path, String value) {
+ Object objectForPath = jsonArray.opt(Integer.parseInt(path.get(0)));
+ if (objectForPath == null) {
+ if (path.size() > 1) {
+ if (StringUtils.isNumeric(path.get(1))) {
+ objectForPath = new JSONArray();
+ } else {
+ objectForPath = new JSONObject();
+ }
+ jsonArray.put(Integer.parseInt(path.get(0)), objectForPath);
+ }
+ }
+
+ if (path.size() == 1) {
+ Object valueAsObject = new Yaml().loadAs(value, Object.class);
+ jsonArray.put(Integer.parseInt(path.get(0)), valueAsObject);
+ } else {
+ if (objectForPath instanceof JSONObject) {
+ addE((JSONObject) objectForPath, path.subList(1, path.size()), value);
+ } else {
+ addE((JSONArray) objectForPath, path.subList(1, path.size()), value);
+ }
+ }
+ }
+
+ private void addE(JSONObject jsonObject, List<String> path, String value) {
+
+ Object objectForPath = null;
+ if (jsonObject.has(path.get(0))) {
+ objectForPath = jsonObject.get(path.get(0));
+ } else {
+ if (path.size() > 1 && StringUtils.isNumeric(path.get(1))) {
+ objectForPath = new JSONArray();
+ } else {
+ objectForPath = new JSONObject();
+ }
+ jsonObject.put(path.get(0), objectForPath);
+ }
+
+ if (path.size() == 1) {
+ Object valueAsObject = new Yaml().loadAs(value, Object.class);
+ jsonObject.put(path.get(0), valueAsObject);
+ } else {
+ if (objectForPath instanceof JSONObject) {
+ addE((JSONObject) objectForPath, path.subList(1, path.size()), value);
+ } else {
+ addE((JSONArray) objectForPath, path.subList(1, path.size()), value);
+ }
+ }
+ }
+
+ private void setJsonObjectForSubProperty(final JSONObject jObject, final List<String> path, String value) {
+ if (path.size() == 1) {
+ Object valueAsObject = new Yaml().loadAs(value, Object.class);
+ jObject.put(path.get(0), valueAsObject);
+ } else {
+ if (!jObject.has(path.get(0))) {
+ jObject.put(path.get(0), new JSONObject());
+ }
+ final JSONObject jsonObject = jObject.getJSONObject(path.get(0));
+ setJsonObjectForSubProperty(jsonObject, path.subList(1, path.size()), value);
+ }
+ }
+
public Either<List<ComponentInstanceAttribute>, ResponseFormat> createOrUpdateAttributeValues(final ComponentTypeEnum componentTypeEnum,
final String componentId,
final String resourceInstanceId,
}
final ComponentInstance foundResourceInstance = resourceInstanceStatus.left().value();
+ // Validate instance attributes against it's constraints
+ List<PropertyDefinition> attributesToValidate = new ArrayList<>();
+ attributes.forEach((componentInstanceAttribute) -> {
+ PropertyDefinition propertyDefinition = new PropertyDefinition();
+ propertyDefinition.setValue(componentInstanceAttribute.getValue());
+ propertyDefinition.setType(componentInstanceAttribute.getType());
+ propertyDefinition.setName(componentInstanceAttribute.getName());
+ propertyDefinition.setUniqueId(componentInstanceAttribute.getUniqueId());
+ attributesToValidate.add(propertyDefinition);
+ });
+ Either<Boolean, ResponseFormat> constraintValidatorResponse = validatePropertyValueConstraint(attributesToValidate, componentId);
+ if (constraintValidatorResponse.isRight()) {
+ log.error("Failed validation value and constraint of attribute: {}", constraintValidatorResponse.right().value());
+ return Either.right(constraintValidatorResponse.right().value());
+ }
+
// lock resource
final StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType());
if (lockStatus != StorageOperationStatus.OK) {
}
private void validatePropertyExistsOnComponent(ComponentInstanceProperty property, Component containerComponent,
- ComponentInstance foundResourceInstance) {
+ ComponentInstance foundResourceInstance) {
List<ComponentInstanceProperty> instanceProperties = containerComponent.getComponentInstancesProperties()
.get(foundResourceInstance.getUniqueId());
final boolean hasProperty = instanceProperties.stream().anyMatch(p -> p.getName().equals(property.getName()));
// Specific Update Logic
String newValue = property.getValue();
- if (property.hasToscaFunction()) {
+ if (property.hasToscaFunction() || CollectionUtils.isNotEmpty(property.getSubPropertyToscaFunctions())) {
return Either.left(newValue);
}
referredProperty = findSubProperty(referredProperty, toscaGetFunction, model);
}
- if (!property.getType().equals(referredProperty.getType())) {
+ if (!property.getType().equals(referredProperty.getType()) && !"list".equalsIgnoreCase(referredProperty.getType())) {
throw ToscaGetFunctionExceptionSupplier
.propertyTypeDiverge(toscaGetFunction.getType(), referredProperty.getType(), property.getType()).get();
}
- if (PropertyType.typeHasSchema(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getSchemaType())) {
+ if (PropertyType.typeHasSchema(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getType())
+ && !"list".equalsIgnoreCase(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getSchemaType())) {
throw ToscaGetFunctionExceptionSupplier
.propertySchemaDiverge(toscaGetFunction.getType(), referredProperty.getSchemaType(), property.getSchemaType()).get();
}
}
Component eitherOriginComponent = getInstanceOriginNode(currentResourceInstance);
- DataForMergeHolder dataHolder = compInstMergeDataBL
- .saveAllDataBeforeDeleting(containerComponent, currentResourceInstance, eitherOriginComponent);
+ DataForMergeHolder dataHolder = compInstMergeDataBL.saveAllDataBeforeDeleting(containerComponent, currentResourceInstance, eitherOriginComponent);
ComponentInstance resResourceInfo = deleteComponentInstance(containerComponent, componentInstanceId,
containerComponentType);
maintainNodeFilters(currentResourceInstance, newComponentInstance, containerComponentId);
- resourceInstanceStatus = getResourceInstanceById(updatedComponentRes.left().value(),
- updatedComponentInstance.getUniqueId());
+ resourceInstanceStatus = getResourceInstanceById(updatedComponentRes.left().value(), updatedComponentInstance.getUniqueId());
if (resourceInstanceStatus.isRight()) {
throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse
(resourceInstanceStatus.right().value()), updatedComponentInstance.getUniqueId());
}
private void maintainNodeFilters(
- ComponentInstance currentResourceInstance,
- ComponentInstance newComponentInstance,
- String containerComponentId) {
+ ComponentInstance currentResourceInstance,
+ ComponentInstance newComponentInstance,
+ String containerComponentId) {
CINodeFilterDataDefinition filterToMaintain = currentResourceInstance.getNodeFilter();
if (null != filterToMaintain) {
nodeFilterOperation.addNodeFilterData(
- containerComponentId.toLowerCase(),
- newComponentInstance.getUniqueId(),
- filterToMaintain);
+ containerComponentId.toLowerCase(),
+ newComponentInstance.getUniqueId(),
+ filterToMaintain);
}
}
private void checkForExternalReqAndCapabilities(Component component, ComponentInstance resResourceInfo) {
- Map<String, List<RequirementDefinition>> requirementsMap = resResourceInfo.getRequirements();
- Map<String, List<RequirementDefinition>> externalRequirementsMap = new HashMap<>();
- List<RequirementDefinition> externalRequirementList = new ArrayList<>();
- if (requirementsMap != null && !requirementsMap.isEmpty()) {
- requirementsMap.forEach((type, requirementDefinitions) -> {
- if (requirementDefinitions != null && !requirementDefinitions.isEmpty()) {
- for (final RequirementDefinition requirementDefinition : requirementDefinitions) {
- if (requirementDefinition.isExternal()) {
- externalRequirementList.add(requirementDefinition);
- externalRequirementsMap.put(type, externalRequirementList);
- }
+ if (MapUtils.isNotEmpty(component.getRequirements())) {
+ component.getRequirements().entrySet().forEach(requirementsMap -> {
+ if (MapUtils.isNotEmpty(resResourceInfo.getRequirements()) &&
+ resResourceInfo.getRequirements().containsKey(requirementsMap.getKey())) {
+ List<RequirementDefinition> resourceReqList = resResourceInfo.getRequirements().get(requirementsMap.getKey());
+ for (RequirementDefinition requirements : requirementsMap.getValue()) {
+ String requirementName = requirements.getName();
+ resourceReqList.forEach(requirementDefinition -> {
+ if (requirementName.equals(requirementDefinition.getName()) && requirementDefinition.isExternal()) {
+ requirements.setExternal(requirementDefinition.isExternal());
+ }
+ });
}
}
});
}
-
- Map<String, List<CapabilityDefinition>> capabilitiesMap = resResourceInfo.getCapabilities();
- Map<String, List<CapabilityDefinition>> externalCapabilitiesMap = new HashMap<>();
- List<CapabilityDefinition> externalCapabilitiesList = new ArrayList<>();
- if (capabilitiesMap != null && !capabilitiesMap.isEmpty()) {
- capabilitiesMap.forEach((type, capabilityDefinitions) -> {
- if (capabilityDefinitions != null && !capabilityDefinitions.isEmpty()) {
- for (final CapabilityDefinition capabilityDefinition : capabilityDefinitions) {
- if (capabilityDefinition.isExternal()) {
- externalCapabilitiesList.add(capabilityDefinition);
- externalCapabilitiesMap.put(type, externalCapabilitiesList);
+ if (MapUtils.isNotEmpty(component.getCapabilities())) {
+ component.getCapabilities().entrySet().forEach(capabilityMap -> {
+ if (MapUtils.isNotEmpty(resResourceInfo.getCapabilities()) && resResourceInfo.getCapabilities().containsKey(capabilityMap.getKey())) {
+ List<CapabilityDefinition> resourceCapList = resResourceInfo.getCapabilities().get(capabilityMap.getKey());
+ capabilityMap.getValue().forEach(capabilities -> {
+ String capabilityName = capabilities.getName();
+ for (CapabilityDefinition capDef : resourceCapList) {
+ if (capabilityName.equals(capDef.getName()) && capDef.isExternal()) {
+ capabilities.setExternal(capDef.isExternal());
+ }
}
- }
+ });
}
});
}
- component.setCapabilities(externalCapabilitiesMap);
- component.setRequirements(externalRequirementsMap);
}
private boolean isFillProxyRes(StorageOperationStatus fillProxyRes) {
containerComponentId);
}
- List<ComponentInstanceProperty> instanceProperties = containerComponent.getComponentInstancesProperties().get(componentInstanceUniqueId);
- if (CollectionUtils.isEmpty(instanceProperties)) {
- instanceProperties = new ArrayList<>();
+ List<ComponentInstanceProperty> instanceProperties = new ArrayList<>();
+ if (MapUtils.isNotEmpty(containerComponent.getComponentInstancesProperties())) {
+ instanceProperties = containerComponent.getComponentInstancesProperties()
+ .get(componentInstanceUniqueId);
}
return instanceProperties;
} catch (ComponentException e) {
if (sourceAttributeName.equals(destAttribute.getName())) {
log.debug("Start to copy the attribute exists {}", sourceAttributeName);
sourceAttribute.setUniqueId(
- UniqueIdBuilder.buildResourceInstanceUniuqeId("attribute", destComponentInstanceId.split("\\.")[1], sourceAttributeName));
+ UniqueIdBuilder.buildResourceInstanceUniqueId("attribute", destComponentInstanceId.split("\\.")[1], sourceAttributeName));
Either<ComponentInstanceAttribute, ResponseFormat> updateAttributeValueEither = createOrUpdateAttributeValueForCopyPaste(
ComponentTypeEnum.SERVICE, destComponent.getUniqueId(), destComponentInstanceId, sourceAttribute, userId);
if (updateAttributeValueEither.isRight()) {
}
}
+ private void validatePropertyConstraintsNotChanged(List<ComponentInstanceProperty> newProperties, ComponentInstance originalResourceInstance) {
+ for (ComponentInstanceProperty newProperty : newProperties) {
+ Optional<PropertyDefinition> originalProperty = originalResourceInstance.getProperties().stream()
+ .filter(prop -> prop.getUniqueId().equals(newProperty.getUniqueId())).findAny();
+ if (originalProperty.isPresent()) {
+ List<PropertyConstraint> originalConstraints = originalProperty.get().getConstraints();
+ List<PropertyConstraint> newConstraints = newProperty.getConstraints();
+ if (!Objects.equals(originalConstraints, newConstraints)) {
+ throw new ByActionStatusComponentException(ActionStatus.CANNOT_CHANGE_CONSTRAINTS);
+ }
+ } else {
+ throw new ByActionStatusComponentException(ActionStatus.PROPERTY_NOT_FOUND, newProperty.getUniqueId());
+ }
+ }
+ }
+
+ private Either<Boolean, ResponseFormat> validatePropertyValueConstraint(List<? extends PropertyDefinition> properties, final String componentId) {
+ try {
+ String propertyModel = propertyBusinessLogic.getComponentModelByComponentId(componentId);
+ PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil = new PropertyValueConstraintValidationUtil();
+ return propertyValueConstraintValidationUtil.validatePropertyConstraints(properties, applicationDataTypeCache, propertyModel);
+ } catch (BusinessLogicException e) {
+ return Either.right(e.getResponseFormat());
+ }
+ }
+
public void validateUser(final String userId) {
final User user = userValidations.validateUserExists(userId);
userValidations.validateUserRole(user, Arrays.asList(Role.DESIGNER, Role.ADMIN));