2 * ============LICENSE_START=======================================================
4 * Copyright (C) 2020 Nordix Foundation
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.be.model.operations.impl;
23 import com.google.gson.JsonElement;
24 import fj.data.Either;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
29 import java.util.Map.Entry;
30 import org.apache.commons.lang3.tuple.ImmutablePair;
31 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
32 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
33 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
34 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
35 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
36 import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
37 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
38 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
39 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
40 import org.openecomp.sdc.be.model.DataTypeDefinition;
41 import org.openecomp.sdc.be.model.PropertyDefinition;
42 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
43 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
44 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
45 import org.openecomp.sdc.be.resources.data.DataTypeData;
46 import org.openecomp.sdc.be.resources.data.PropertyData;
47 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
48 import org.openecomp.sdc.common.log.wrappers.Logger;
49 import org.springframework.beans.factory.annotation.Autowired;
50 import org.springframework.stereotype.Component;
53 @Component("attribute-operation")
54 public class AttributeOperation extends AbstractOperation {
56 private static Logger log = Logger.getLogger(AttributeOperation.class.getName());
58 private static final String FAILED_TO_FETCH_ATTRIBUTES_OF_DATA_TYPE = "Failed to fetch attributes of data type {}";
59 private static final String DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS = "Data type {} cannot be found in graph. status is {}";
60 private static final String THE_VALUE_OF_ATTRIBUTE_FROM_TYPE_IS_INVALID = "The value {} of attribute from type {} is invalid";
64 public AttributeOperation(HealingJanusGraphGenericDao janusGraphGenericDao) {
65 this.janusGraphGenericDao = janusGraphGenericDao;
68 public boolean isAttributeTypeValid(final AttributeDataDefinition attributeDefinition) {
70 if (attributeDefinition == null) {
74 if (ToscaPropertyType.isValidType(attributeDefinition.getType()) == null) {
75 final Either<Boolean, JanusGraphOperationStatus> definedInDataTypes = isDefinedInDataTypes(
76 attributeDefinition.getType());
78 if (definedInDataTypes.isRight()) {
81 Boolean isExist = definedInDataTypes.left().value();
82 return isExist.booleanValue();
89 public Either<Boolean, JanusGraphOperationStatus> isDefinedInDataTypes(final String propertyType) {
91 final String dataTypeUid = UniqueIdBuilder.buildDataTypeUid(propertyType);
92 final Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeByUid = getDataTypeByUid(dataTypeUid);
93 if (dataTypeByUid.isRight()) {
94 final JanusGraphOperationStatus status = dataTypeByUid.right().value();
95 if (status == JanusGraphOperationStatus.NOT_FOUND) {
96 return Either.left(false);
98 return Either.right(status);
101 return Either.left(true);
106 * Build Data type object from graph by unique id
108 public Either<DataTypeDefinition, JanusGraphOperationStatus> getDataTypeByUid(final String uniqueId) {
110 final Either<DataTypeData, JanusGraphOperationStatus> dataTypesRes = janusGraphGenericDao
111 .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, DataTypeData.class);
113 if (dataTypesRes.isRight()) {
114 JanusGraphOperationStatus status = dataTypesRes.right().value();
115 log.debug(DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS, uniqueId, status);
116 return Either.right(status);
119 final DataTypeData ctData = dataTypesRes.left().value();
120 final DataTypeDefinition dataTypeDefinition = new DataTypeDefinition(ctData.getDataTypeDataDefinition());
122 final JanusGraphOperationStatus propertiesStatus = fillProperties(uniqueId, dataTypeDefinition);
123 if (propertiesStatus != JanusGraphOperationStatus.OK) {
124 log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, FAILED_TO_FETCH_ATTRIBUTES_OF_DATA_TYPE, uniqueId);
125 return Either.right(propertiesStatus);
128 final Either<ImmutablePair<DataTypeData, GraphEdge>, JanusGraphOperationStatus> parentNode = janusGraphGenericDao
129 .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, GraphEdgeLabels.DERIVED_FROM,
130 NodeTypeEnum.DataType,
132 log.debug("After retrieving DERIVED_FROM node of {}. status is {}", uniqueId, parentNode);
133 if (parentNode.isRight()) {
134 final JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
135 if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
136 log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR,
137 "Failed to find the parent data type of data type {}. status is {}", uniqueId,
138 janusGraphOperationStatus);
139 return Either.right(janusGraphOperationStatus);
142 // derived from node was found
143 final ImmutablePair<DataTypeData, GraphEdge> immutablePair = parentNode.left().value();
144 final DataTypeData parentCT = immutablePair.getKey();
146 final String parentUniqueId = parentCT.getUniqueId();
147 final Either<DataTypeDefinition, JanusGraphOperationStatus> dataTypeByUid = getDataTypeByUid(
150 if (dataTypeByUid.isRight()) {
151 return Either.right(dataTypeByUid.right().value());
154 final DataTypeDefinition parentDataTypeDefinition = dataTypeByUid.left().value();
156 dataTypeDefinition.setDerivedFrom(parentDataTypeDefinition);
159 return Either.left(dataTypeDefinition);
162 private JanusGraphOperationStatus fillProperties(final String uniqueId,
163 final DataTypeDefinition dataTypeDefinition) {
165 final Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> findPropertiesOfNode = this
166 .findPropertiesOfNode(NodeTypeEnum.DataType, uniqueId);
167 if (findPropertiesOfNode.isRight()) {
168 final JanusGraphOperationStatus janusGraphOperationStatus = findPropertiesOfNode.right().value();
169 log.debug("After looking for properties of vertex {}. status is {}", uniqueId,
170 janusGraphOperationStatus);
171 if (JanusGraphOperationStatus.NOT_FOUND.equals(janusGraphOperationStatus)) {
172 return JanusGraphOperationStatus.OK;
174 return janusGraphOperationStatus;
177 final Map<String, PropertyDefinition> properties = findPropertiesOfNode.left().value();
178 if (properties != null && !properties.isEmpty()) {
179 List<PropertyDefinition> listOfProps = new ArrayList<>();
181 for (final Entry<String, PropertyDefinition> entry : properties.entrySet()) {
182 final String propName = entry.getKey();
183 final PropertyDefinition propertyDefinition = entry.getValue();
184 final PropertyDefinition newPropertyDefinition = new PropertyDefinition(propertyDefinition);
185 newPropertyDefinition.setName(propName);
186 listOfProps.add(newPropertyDefinition);
188 dataTypeDefinition.setProperties(listOfProps);
190 return JanusGraphOperationStatus.OK;
194 public Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> findPropertiesOfNode(
195 final NodeTypeEnum nodeType, final String uniqueId) {
197 final Map<String, PropertyDefinition> resourceProps = new HashMap<>();
199 final Either<List<ImmutablePair<PropertyData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
200 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(nodeType), uniqueId, GraphEdgeLabels.PROPERTY,
201 NodeTypeEnum.Property,
204 if (childrenNodes.isRight()) {
205 final JanusGraphOperationStatus operationStatus = childrenNodes.right().value();
206 return Either.right(operationStatus);
209 final List<ImmutablePair<PropertyData, GraphEdge>> values = childrenNodes.left().value();
210 if (values != null) {
211 for (final ImmutablePair<PropertyData, GraphEdge> immutablePair : values) {
212 final GraphEdge edge = immutablePair.getValue();
213 final String propertyName = (String) edge.getProperties().get(GraphPropertiesDictionary.NAME.getProperty());
214 log.debug("Attribute {} is associated to node {}", propertyName, uniqueId);
215 final PropertyData propertyData = immutablePair.getKey();
216 final PropertyDefinition propertyDefinition = this
217 .convertPropertyDataToPropertyDefinition(propertyData, propertyName);
218 resourceProps.put(propertyName, propertyDefinition);
223 log.debug("The properties associated to node {} are {}", uniqueId, resourceProps);
224 return Either.left(resourceProps);
227 public PropertyDefinition convertPropertyDataToPropertyDefinition(final PropertyData propertyDataResult,
228 final String propertyName) {
229 log.debug("The object returned after create property is {}", propertyDataResult);
231 final PropertyDefinition propertyDefResult = new PropertyDefinition(propertyDataResult.getPropertyDataDefinition());
232 propertyDefResult.setConstraints(convertConstraints(propertyDataResult.getConstraints()));
233 propertyDefResult.setName(propertyName);
235 return propertyDefResult;
239 public ImmutablePair<String, Boolean> isAttributeInnerTypeValid(final AttributeDataDefinition attributeDefinition,
240 final Map<String, DataTypeDefinition> dataTypes) {
242 if (attributeDefinition == null) {
243 return new ImmutablePair<>(null, false);
246 SchemaDefinition schema;
247 PropertyDataDefinition innerProp;
248 String innerType = null;
249 if ((schema = attributeDefinition.getSchema()) != null && ((innerProp = schema.getProperty()) != null)) {
250 innerType = innerProp.getType();
253 final ToscaPropertyType innerToscaType = ToscaPropertyType.isValidType(innerType);
255 if (innerToscaType == null) {
256 final DataTypeDefinition dataTypeDefinition = dataTypes.get(innerType);
257 if (dataTypeDefinition == null) {
258 log.debug("The inner type {} is not a data type.", innerType);
259 return new ImmutablePair<>(innerType, false);
261 log.debug("The inner type {} is a data type. Data type definition is {}", innerType,
265 return new ImmutablePair<>(innerType, true);
269 public boolean isAttributeDefaultValueValid(final AttributeDataDefinition attributeDefinition,
270 final Map<String, DataTypeDefinition> dataTypes) {
271 if (attributeDefinition == null) {
275 String innerType = null;
276 final String propertyType = attributeDefinition.getType();
277 final ToscaPropertyType type = getType(propertyType);
278 if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
279 final SchemaDefinition def = attributeDefinition.getSchema();
283 final PropertyDataDefinition propDef = def.getProperty();
284 if (propDef == null) {
287 innerType = propDef.getType();
289 final String value = (String) attributeDefinition.get_default();
291 isValid = isValidValue(type, value, innerType, dataTypes);
293 log.trace("The given type {} is not a pre defined one.", propertyType);
295 final DataTypeDefinition foundDt = dataTypes.get(propertyType);
296 if (foundDt != null) {
297 isValid = isValidComplexValue(foundDt, value, dataTypes);
305 private boolean isValidComplexValue(final DataTypeDefinition foundDt, final String value,
306 final Map<String, DataTypeDefinition> dataTypes) {
307 final ImmutablePair<JsonElement, Boolean> validateAndUpdate = dataTypeValidatorConverter
308 .validateAndUpdate(value, foundDt, dataTypes);
310 log.trace("The result after validating complex value of type {} is {}", foundDt.getName(), validateAndUpdate);
312 return validateAndUpdate.right.booleanValue();
317 public StorageOperationStatus validateAndUpdateAttribute(final AttributeDataDefinition attributeDefinition,
318 final Map<String, DataTypeDefinition> dataTypes) {
320 log.trace("Going to validate attribute type and value. {}", attributeDefinition);
322 final String attributeDefinitionType = attributeDefinition.getType();
323 final String value = (String) attributeDefinition.get_default();
325 final ToscaPropertyType type = getType(attributeDefinitionType);
329 final DataTypeDefinition dataTypeDefinition = dataTypes.get(attributeDefinitionType);
330 if (dataTypeDefinition == null) {
331 log.debug("The type {} of attribute cannot be found.", attributeDefinitionType);
332 return StorageOperationStatus.INVALID_TYPE;
335 return validateAndUpdateAttributeComplexValue(attributeDefinition, attributeDefinitionType, value,
336 dataTypeDefinition, dataTypes);
341 final Either<String, JanusGraphOperationStatus> checkInnerType = getInnerType(type, attributeDefinition::getSchema);
342 if (checkInnerType.isRight()) {
343 return StorageOperationStatus.INVALID_TYPE;
345 innerType = checkInnerType.left().value();
347 log.trace("After validating property type {}", attributeDefinitionType);
349 if (!isValidValue(type, value, innerType, dataTypes)) {
350 log.info(THE_VALUE_OF_ATTRIBUTE_FROM_TYPE_IS_INVALID, value, type);
351 return StorageOperationStatus.INVALID_VALUE;
354 final PropertyValueConverter converter = type.getConverter();
356 if (isEmptyValue(value)) {
357 log.debug("Default value was not sent for attribute {}. Set default value to {}",
358 attributeDefinition.getName(), EMPTY_VALUE);
359 attributeDefinition.set_default(EMPTY_VALUE);
360 } else if (!isEmptyValue(value)) {
361 attributeDefinition.set_default(converter.convert(value, innerType, dataTypes));
363 return StorageOperationStatus.OK;
366 private StorageOperationStatus validateAndUpdateAttributeComplexValue(
367 final AttributeDataDefinition attributeDefinition,
368 final String attributeType,
370 final DataTypeDefinition dataTypeDefinition,
371 final Map<String, DataTypeDefinition> dataTypes) {
373 final ImmutablePair<JsonElement, Boolean> validateResult = dataTypeValidatorConverter
374 .validateAndUpdate(value, dataTypeDefinition, dataTypes);
375 if (!validateResult.right.booleanValue()) {
376 log.debug(THE_VALUE_OF_ATTRIBUTE_FROM_TYPE_IS_INVALID, attributeType, attributeType);
377 return StorageOperationStatus.INVALID_VALUE;
379 final JsonElement jsonElement = validateResult.left;
380 if (log.isTraceEnabled()) {
381 log.trace("Going to update value in attribute definition {} {}", attributeDefinition.getName(),
382 (jsonElement != null ? jsonElement.toString() : null));
384 updateAttributeValue(attributeDefinition, jsonElement);
385 return StorageOperationStatus.OK;
388 private void updateAttributeValue(final AttributeDataDefinition attributeDefinition,
389 final JsonElement jsonElement) {
390 attributeDefinition.set_default(jsonElement);