From 0411615fe4f55fe3463da2576de376c7478fcfb2 Mon Sep 17 00:00:00 2001 From: MichaelMorris Date: Fri, 26 Aug 2022 11:00:03 +0100 Subject: [PATCH] Support TOSCA functions in sub properties Change-Id: Ibfd95c928bbb10089cfc9749ae4e7b05270e3d68 Issue-ID: SDC-4151 Signed-off-by: MichaelMorris --- .../impl/ComponentInstanceBusinessLogic.java | 26 +++++++++++++++- .../models/properties-inputs/property-be-model.ts | 3 ++ .../src/app/models/sub-property-tosca-function.ts | 28 +++++++++++++++++ .../dynamic-property.component.html | 2 +- .../dynamic-property/dynamic-property.component.ts | 3 +- .../properties-assignment.page.component.ts | 36 ++++++++++++++++++++-- .../services/hierarchy-nav.service.ts | 1 + .../services/properties.utils.ts | 18 +++++++++++ .../tosca-function/tosca-function.component.ts | 21 ++++++++++++- .../tosca-get-function.component.ts | 24 +++++++++++++-- .../datatypes/elements/PropertyDataDefinition.java | 3 ++ .../elements/SubPropertyToscaFunction.java | 32 +++++++++++++++++++ 12 files changed, 189 insertions(+), 8 deletions(-) create mode 100644 catalog-ui/src/app/models/sub-property-tosca-function.ts create mode 100644 common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/SubPropertyToscaFunction.java diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java index 5b15138ad4..684645a7b2 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java @@ -43,6 +43,7 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; +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; @@ -1967,6 +1968,13 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { toscaFunctionValidator.validate(property, containerComponent); property.setValue(property.getToscaFunction().getValue()); } + if (CollectionUtils.isNotEmpty(property.getSubPropertyToscaFunctions())){ + final JSONObject jObject = property.getValue() == null ? new JSONObject() : new JSONObject(property.getValue()); + property.getSubPropertyToscaFunctions().stream().forEach(subToscaFunction -> { + setJsonObjectForSubProperty(jObject, subToscaFunction.getSubPropertyPath(), subToscaFunction.getToscaFunction().getValue()); + }); + property.setValue(jObject.toString()); + } Either updatedPropertyValue = updatePropertyObjectValue(property, containerComponent.getModel()); if (updatedPropertyValue.isRight()) { log.error("Failed to update property object value of property: {}", @@ -2011,6 +2019,22 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { graphLockOperation.unlockComponent(componentId, componentTypeEnum.getNodeType()); } } + + private void setJsonObjectForSubProperty(final JSONObject jObject, final List path, String value) { + if (path.size() == 1) { + if (!value.startsWith("{")) { + value = new StringBuilder("{").append(value).append("}").toString(); + } + final JSONObject jObjectSub = new JSONObject(value); + jObject.put(path.get(0), jObjectSub); + } 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, ResponseFormat> createOrUpdateAttributeValues(final ComponentTypeEnum componentTypeEnum, final String componentId, @@ -2300,7 +2324,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { // Specific Update Logic String newValue = property.getValue(); - if (property.hasToscaFunction()) { + if (property.hasToscaFunction() || CollectionUtils.isNotEmpty(property.getSubPropertyToscaFunctions())) { return Either.left(newValue); } diff --git a/catalog-ui/src/app/models/properties-inputs/property-be-model.ts b/catalog-ui/src/app/models/properties-inputs/property-be-model.ts index 9429036f6e..097bbb2c54 100644 --- a/catalog-ui/src/app/models/properties-inputs/property-be-model.ts +++ b/catalog-ui/src/app/models/properties-inputs/property-be-model.ts @@ -23,6 +23,7 @@ import {SchemaProperty, SchemaPropertyGroupModel} from '../schema-property'; import {ToscaPresentationData} from '../tosca-presentation'; import {PropertyInputDetail} from './property-input-detail'; import {Metadata} from '../metadata'; +import {SubPropertyToscaFunction} from "../sub-property-tosca-function"; import {ToscaFunction} from "../tosca-function"; import {ToscaGetFunction} from "../tosca-get-function"; import {ToscaGetFunctionTypeConverter} from "../tosca-get-function-type-converter"; @@ -74,6 +75,7 @@ export class PropertyBEModel { */ toscaGetFunction: ToscaGetFunctionDto; toscaFunction: ToscaFunction; + subPropertyToscaFunctions: SubPropertyToscaFunction[]; constructor(property?: PropertyBEModel) { if (property) { @@ -114,6 +116,7 @@ export class PropertyBEModel { toscaGetFunction1.propertyPathFromSource = property.toscaGetFunction.propertyPathFromSource; this.toscaFunction = toscaGetFunction1; } + this.subPropertyToscaFunctions = property.subPropertyToscaFunctions; } if (!this.schema || !this.schema.property) { diff --git a/catalog-ui/src/app/models/sub-property-tosca-function.ts b/catalog-ui/src/app/models/sub-property-tosca-function.ts new file mode 100644 index 0000000000..4c43a8780f --- /dev/null +++ b/catalog-ui/src/app/models/sub-property-tosca-function.ts @@ -0,0 +1,28 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import {ToscaFunction} from "./tosca-function"; + +export class SubPropertyToscaFunction { + toscaFunction: ToscaFunction; + subPropertyPath: string[]; + +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html index f855265157..4553bcbd01 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html @@ -21,7 +21,7 @@
- +
{{property.name}}
diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts index 6107e8ad50..8c8d1e28ba 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts @@ -143,8 +143,9 @@ export class DynamicPropertyComponent { }; createNewChildProperty = (): void => { - + let newProps: Array = this.propertiesUtils.createListOrMapChildren(this.property, "", null); + this.propertiesUtils.assignFlattenedChildrenValues(this.property.valueObj, [newProps[0]], this.property.propertiesName); if (this.property instanceof PropertyFEModel) { this.addChildProps(newProps, this.property.name); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts index 893cddd4b9..c3babc1e03 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts @@ -38,7 +38,8 @@ import { PropertyBEModel, PropertyFEModel, Service, - SimpleFlatProperty + SimpleFlatProperty, + PropertyDeclareAPIModel } from "app/models"; import {ResourceType} from "app/utils"; import {ComponentServiceNg2} from "../../services/component-services/component.service"; @@ -67,6 +68,7 @@ import {ToscaPresentationData} from "../../../models/tosca-presentation"; import {Observable} from "rxjs"; import {TranslateService} from "../../shared/translator/translate.service"; import {ToscaFunction} from "../../../models/tosca-function"; +import {SubPropertyToscaFunction} from "../../../models/sub-property-tosca-function"; const SERVICE_SELF_TITLE = "SELF"; @Component({ @@ -579,6 +581,14 @@ export class PropertiesAssignmentComponent { checkedInstanceProperty.getInputValues = null; checkedInstanceProperty.value = null; checkedInstanceProperty.toscaFunction = null; + if (checkedInstanceProperty instanceof PropertyDeclareAPIModel && (checkedInstanceProperty).propertiesName){ + const propertiesNameArray = (checkedInstanceProperty).propertiesName; + const parts = propertiesNameArray.split("#"); + if (propertiesNameArray.length > 1){ + const index = checkedInstanceProperty.subPropertyToscaFunctions.findIndex(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, parts.slice(1))); + checkedInstanceProperty.subPropertyToscaFunctions.splice(index, 1); + } + } if (this.selectedInstanceData instanceof ComponentInstance) { this.updateInstanceProperty(checkedInstanceProperty); } else if (this.selectedInstanceData instanceof GroupInstance) { @@ -590,7 +600,25 @@ export class PropertiesAssignmentComponent { private updateCheckedInstancePropertyFunctionValue(toscaFunction: ToscaFunction) { const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty(); - checkedProperty.toscaFunction = toscaFunction; + if (checkedProperty instanceof PropertyDeclareAPIModel && (checkedProperty).propertiesName){ + const propertiesName = (checkedProperty).propertiesName; + const parts = propertiesName.split("#"); + + if (checkedProperty.subPropertyToscaFunctions == null){ + checkedProperty.subPropertyToscaFunctions = []; + } + let subPropertyToscaFunction = checkedProperty.subPropertyToscaFunctions.find(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, parts.slice(1))); + if (!subPropertyToscaFunction){ + subPropertyToscaFunction = new SubPropertyToscaFunction(); + checkedProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction); + } + subPropertyToscaFunction.toscaFunction = toscaFunction; + subPropertyToscaFunction.subPropertyPath = parts.slice(1); + + } else { + checkedProperty.subPropertyToscaFunctions = null; + checkedProperty.toscaFunction = toscaFunction; + } if (this.selectedInstanceData instanceof ComponentInstance) { this.updateInstanceProperty(checkedProperty); } else if (this.selectedInstanceData instanceof GroupInstance) { @@ -600,6 +628,10 @@ export class PropertiesAssignmentComponent { } } + private areEqual(array1: string[], array2: string[]): boolean { + return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]}) + } + updateInstanceProperty(instanceProperty: PropertyBEModel) { this.loadingProperties = true; this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId, diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/services/hierarchy-nav.service.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/services/hierarchy-nav.service.ts index 1a800baac7..e3baad6cb2 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/services/hierarchy-nav.service.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/services/hierarchy-nav.service.ts @@ -44,6 +44,7 @@ export class HierarchyNavService { }); let tree = this.unflatten(flattenProperties, '', []); + return tree[0].childrens; // Return the childrens without the root. } diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts index 8e9be8b9a0..753cb6afe0 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts @@ -24,6 +24,7 @@ import { DataTypeModel, PropertyFEModel, PropertyBEModel, InstanceBePropertiesMa import { DataTypeService } from "app/ng2/services/data-type.service"; import { PropertiesService } from "app/ng2/services/properties.service"; import { PROPERTY_TYPES, PROPERTY_DATA } from "app/utils"; +import { SubPropertyToscaFunction } from "app/models/sub-property-tosca-function"; @Injectable() export class PropertiesUtils { @@ -143,14 +144,31 @@ export class PropertiesUtils { } else if (property.derivedDataType === DerivedPropertyType.COMPLEX) { property.flattenedChildren = this.createFlattenedChildren(property.type, property.name); this.assignFlattenedChildrenValues(property.valueObj, property.flattenedChildren, property.name); + this.setFlattenedChildernToscaFunction(property.subPropertyToscaFunctions, property.flattenedChildren, property.name); property.flattenedChildren.forEach((childProp) => { property.childPropUpdated(childProp); }); + } } property.updateValueObjOrig(); }; + public setFlattenedChildernToscaFunction = (subPropertyToscaFunctions: SubPropertyToscaFunction[], derivedPropArray: Array, topLevelPropertyName: string) => { + if (!subPropertyToscaFunctions || !derivedPropArray || !topLevelPropertyName){ + return; + } + derivedPropArray.forEach((prop, index) => { + const subPropertyPath = prop.propertiesName.substring(prop.propertiesName.indexOf(topLevelPropertyName) + topLevelPropertyName.length + 1); + subPropertyToscaFunctions.forEach(subPropertyToscaFunction => { + const toscaFunctionPath = subPropertyToscaFunction.subPropertyPath.join('#'); + if (subPropertyPath === toscaFunctionPath){ + prop.toscaFunction = subPropertyToscaFunction.toscaFunction; + } + }) + }) + } + /* * Loops through flattened properties array and to assign values * Then, convert any neccessary strings to objects, and vis-versa diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts index ae778006ce..70df4eaced 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts @@ -18,7 +18,7 @@ */ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; -import {ComponentMetadata, PropertyBEModel} from 'app/models'; +import {ComponentMetadata, PropertyBEModel, PropertyDeclareAPIModel} from 'app/models'; import {TopologyTemplateService} from "../../../services/component-services/topology-template.service"; import {WorkspaceService} from "../../workspace/workspace.service"; import {ToscaGetFunctionType} from "../../../../models/tosca-get-function-type"; @@ -86,6 +86,21 @@ export class ToscaFunctionComponent implements OnInit { } private initToscaFunction() { + if (this.property instanceof PropertyDeclareAPIModel && this.property.subPropertyToscaFunctions && ( this.property).propertiesName){ + let propertiesPath = ( this.property).propertiesName.split("#"); + if (propertiesPath.length > 1){ + propertiesPath = propertiesPath.slice(1); + let subPropertyToscaFunction = this.property.subPropertyToscaFunctions.find(subPropertyToscaFunction => this.areEqual(subPropertyToscaFunction.subPropertyPath, propertiesPath)); + + if (subPropertyToscaFunction){ + this.toscaFunction = subPropertyToscaFunction.toscaFunction; + this.toscaFunctionForm.setValue(this.toscaFunction); + this.toscaFunctionTypeForm.setValue(this.toscaFunction.type); + } + return; + } + } + if (!this.property.isToscaFunction()) { return; } @@ -93,6 +108,10 @@ export class ToscaFunctionComponent implements OnInit { this.toscaFunctionTypeForm.setValue(this.property.toscaFunction.type); } + private areEqual(array1: string[], array2: string[]): boolean { + return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]}) + } + private loadToscaFunctions(): void { this.toscaFunctions.push(ToscaFunctionType.GET_ATTRIBUTE); this.toscaFunctions.push(ToscaFunctionType.GET_INPUT); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts index 64d155a55f..1f658f968a 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts @@ -18,7 +18,7 @@ */ import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core'; -import {AttributeBEModel, ComponentMetadata, DataTypeModel, PropertyBEModel, PropertyModel} from 'app/models'; +import {AttributeBEModel, ComponentMetadata, DataTypeModel, PropertyBEModel, PropertyModel, PropertyDeclareAPIModel} from 'app/models'; import {TopologyTemplateService} from "../../../../services/component-services/topology-template.service"; import {WorkspaceService} from "../../../workspace/workspace.service"; import {PropertiesService} from "../../../../services/properties.service"; @@ -261,12 +261,19 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges { } private propertyTypeToString() { + if (this.isSubProperty()){ + return this.getType((this.property).propertiesName.split("#").slice(1), this.property.type); + } if (this.property.schemaType) { return `${this.property.type} of ${this.property.schemaType}`; } return this.property.type; } + private isSubProperty(): boolean{ + return this.property instanceof PropertyDeclareAPIModel && (this.property).propertiesName && (this.property).propertiesName.length > 1; + } + private extractProperties(componentGenericResponse: ComponentGenericResponse): Array { if (this.isGetInput()) { return componentGenericResponse.inputs; @@ -358,17 +365,30 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges { }); } - private hasSameType(property: PropertyBEModel | AttributeBEModel) { + private hasSameType(property: PropertyBEModel | AttributeBEModel): boolean { if (this.typeHasSchema(this.property.type)) { if (!property.schema || !property.schema.property) { return false; } return property.type === this.property.type && this.property.schema.property.type === property.schema.property.type; } + if (this.property.schema.property.isDataType && this.property instanceof PropertyDeclareAPIModel && (this.property).propertiesName){ + let typeToMatch = this.getType((this.property).propertiesName.split("#").slice(1), this.property.type); + return property.type === typeToMatch; + } return property.type === this.property.type; } + private getType(propertyPath:string[], type: string): string { + const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, type); + let nestedProperty = dataTypeFound.properties.find(property => property.name === propertyPath[0]); + if (propertyPath.length === 1){ + return nestedProperty.type; + } + return this.getType(propertyPath.slice(1), nestedProperty.type); + } + private isGetProperty(): boolean { return this.functionType === ToscaGetFunctionType.GET_PROPERTY; } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java index adfef9c426..8297ef1984 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java @@ -24,6 +24,7 @@ import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -67,6 +68,7 @@ public class PropertyDataDefinition extends ToscaDataDefinition { @Deprecated private ToscaGetFunctionDataDefinition toscaGetFunction; private ToscaFunction toscaFunction; + private Collection subPropertyToscaFunctions; private String inputPath; private String status; @@ -126,6 +128,7 @@ public class PropertyDataDefinition extends ToscaDataDefinition { this.setToscaFunction(propertyDataDefinition.getToscaFunction()); this.parentPropertyType = propertyDataDefinition.getParentPropertyType(); this.subPropertyInputPath = propertyDataDefinition.getSubPropertyInputPath(); + this.subPropertyToscaFunctions = propertyDataDefinition.getSubPropertyToscaFunctions(); if (isNotEmpty(propertyDataDefinition.annotations)) { this.setAnnotations(propertyDataDefinition.annotations); } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/SubPropertyToscaFunction.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/SubPropertyToscaFunction.java new file mode 100644 index 0000000000..15170c0e6a --- /dev/null +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/SubPropertyToscaFunction.java @@ -0,0 +1,32 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.datatypes.elements; + +import java.util.List; +import lombok.Data; + +@Data +public class SubPropertyToscaFunction { + private ToscaFunction toscaFunction; + private List subPropertyPath; + +} -- 2.16.6