2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
20 package org.openecomp.sdc.be.components.impl;
22 import fj.data.Either;
23 import java.util.ArrayList;
24 import java.util.HashSet;
25 import java.util.List;
28 import java.util.stream.Collectors;
29 import javax.annotation.Resource;
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.commons.lang3.tuple.ImmutablePair;
32 import org.openecomp.sdc.be.components.impl.CommonImportManager.ElementTypeEnum;
33 import org.openecomp.sdc.be.dao.api.ActionStatus;
34 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
35 import org.openecomp.sdc.be.impl.ComponentsUtils;
36 import org.openecomp.sdc.be.model.DataTypeDefinition;
37 import org.openecomp.sdc.be.model.PropertyDefinition;
38 import org.openecomp.sdc.be.model.RelationshipTypeDefinition;
39 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
40 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
41 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
42 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
43 import org.openecomp.sdc.be.utils.TypeUtils;
44 import org.openecomp.sdc.common.log.wrappers.Logger;
45 import org.openecomp.sdc.exception.ResponseFormat;
46 import org.springframework.stereotype.Component;
48 @Component("dataTypeImportManager")
49 public class DataTypeImportManager {
51 private static final Logger log = Logger.getLogger(DataTypeImportManager.class.getName());
53 private PropertyOperation propertyOperation;
55 private ComponentsUtils componentsUtils;
57 private CommonImportManager commonImportManager;
59 public Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat> createDataTypes(final String dataTypeYml, final String modelName) {
60 return commonImportManager
61 .createElementTypes(dataTypeYml, dataTypesFromYml -> createDataTypesFromYml(dataTypeYml, modelName), this::createDataTypesByDao, ElementTypeEnum.DATA_TYPE);
64 private Either<List<DataTypeDefinition>, ActionStatus> createDataTypesFromYml(final String dataTypesYml, final String modelName) {
65 final Either<List<DataTypeDefinition>, ActionStatus> dataTypes = commonImportManager.createElementTypesFromYml(dataTypesYml, this::createDataType);
66 if (dataTypes.isLeft() && StringUtils.isNotEmpty(modelName)){
67 dataTypes.left().value().forEach(dataType -> dataType.setModel(modelName));
72 private Either<List<ImmutablePair<DataTypeDefinition, Boolean>>, ResponseFormat> createDataTypesByDao(
73 List<DataTypeDefinition> dataTypesToCreate) {
74 return commonImportManager.createElementTypesByDao(dataTypesToCreate, this::validateDataType,
75 dataType -> new ImmutablePair<>(ElementTypeEnum.DATA_TYPE, UniqueIdBuilder.buildDataTypeUid(dataType.getModel(), dataType.getName())),
76 dataTypeUid -> propertyOperation.getDataTypeByUidWithoutDerived(dataTypeUid, true), dataType -> propertyOperation.addDataType(dataType),
77 (newDataType, oldDataType) -> propertyOperation.updateDataType(newDataType, oldDataType));
80 private Either<ActionStatus, ResponseFormat> validateDataType(DataTypeDefinition dataType) {
81 String dataTypeName = dataType.getName();
82 List<PropertyDefinition> properties = dataType.getProperties();
83 if (properties == null) {
84 // At least one parameter should be defined either in the properties
86 // section or at one of the parents
87 String derivedDataType = dataType.getDerivedFromName();
88 // If there are no properties, then we can create a data type if it
90 // is an abstract one or it derives from non abstract data type
91 if (derivedDataType == null || derivedDataType.isEmpty()) {
92 if (!isAbstract(dataType.getName()) && !ToscaPropertyType.isScalarType(dataTypeName)) {
93 log.debug("Data type {} must have properties unless it derives from non abstract data type", dataType.getName());
94 ResponseFormat responseFormat = componentsUtils
95 .getResponseFormatByDataType(ActionStatus.DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM, dataType, null);
96 return Either.right(responseFormat);
99 if (!ToscaPropertyType.isScalarType(dataTypeName) && isAbstract(derivedDataType)) {
100 log.warn("Creating data type {} which derived from abstract data type with no properties", dataType.getName());
104 // properties tag cannot be empty
105 if (properties.isEmpty()) {
106 ResponseFormat responseFormat = componentsUtils
107 .getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROPERTIES_CANNOT_BE_EMPTY, dataType, null);
108 return Either.right(responseFormat);
110 // check no duplicates
111 Set<String> collect = properties.stream().map(PropertyDataDefinition::getName).collect(Collectors.toSet());
112 if (collect != null && properties.size() != collect.size()) {
113 ResponseFormat responseFormat = componentsUtils
114 .getResponseFormatByDataType(ActionStatus.DATA_TYPE_DUPLICATE_PROPERTY, dataType, null);
115 return Either.right(responseFormat);
117 List<String> propertiesWithSameTypeAsDataType = properties.stream().filter(p -> p.getType().equals(dataType.getName()))
118 .map(PropertyDataDefinition::getName).collect(Collectors.toList());
119 if (propertiesWithSameTypeAsDataType != null && !propertiesWithSameTypeAsDataType.isEmpty()) {
120 log.debug("The data type {} contains properties with the type {}", dataType.getName(), dataType.getName());
121 ResponseFormat responseFormat = componentsUtils
122 .getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROEPRTY_CANNOT_HAVE_SAME_TYPE_OF_DATA_TYPE, dataType,
123 propertiesWithSameTypeAsDataType);
124 return Either.right(responseFormat);
127 String derivedDataType = dataType.getDerivedFromName();
128 if (derivedDataType != null) {
129 Either<DataTypeDefinition, StorageOperationStatus> derivedDataTypeByName = propertyOperation.getDataTypeByName(derivedDataType, dataType.getModel());
130 if (derivedDataTypeByName.isRight()) {
131 StorageOperationStatus status = derivedDataTypeByName.right().value();
132 if (status == StorageOperationStatus.NOT_FOUND) {
133 ResponseFormat responseFormat = componentsUtils
134 .getResponseFormatByDataType(ActionStatus.DATA_TYPE_DERIVED_IS_MISSING, dataType, null);
135 return Either.right(responseFormat);
137 ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.GENERAL_ERROR, dataType, null);
138 return Either.right(responseFormat);
141 DataTypeDefinition derivedDataTypeDef = derivedDataTypeByName.left().value();
142 if (properties != null && !properties.isEmpty() && derivedDataTypeDef != null) {
143 if (isScalarType(derivedDataTypeDef)) {
144 ResponseFormat responseFormat = componentsUtils
145 .getResponseFormatByDataType(ActionStatus.DATA_TYPE_CANNOT_HAVE_PROPERTIES, dataType, null);
146 return Either.right(responseFormat);
148 Set<String> allParentsProps = new HashSet<>();
150 List<PropertyDefinition> currentParentsProps = derivedDataTypeDef.getProperties();
151 if (currentParentsProps != null) {
152 for (PropertyDefinition propertyDefinition : currentParentsProps) {
153 allParentsProps.add(propertyDefinition.getName());
156 derivedDataTypeDef = derivedDataTypeDef.getDerivedFrom();
157 } while (derivedDataTypeDef != null);
158 // Check that no property is already defined in one of the
161 Set<String> alreadyExistPropsCollection = properties.stream().filter(p -> allParentsProps.contains(p.getName()))
162 .map(PropertyDataDefinition::getName).collect(Collectors.toSet());
163 if (alreadyExistPropsCollection != null && !alreadyExistPropsCollection.isEmpty()) {
164 List<String> duplicateProps = new ArrayList<>();
165 duplicateProps.addAll(alreadyExistPropsCollection);
166 ResponseFormat responseFormat = componentsUtils
167 .getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROPERTY_ALREADY_DEFINED_IN_ANCESTOR, dataType, duplicateProps);
168 return Either.right(responseFormat);
173 return Either.left(ActionStatus.OK);
176 private boolean isAbstract(String dataTypeName) {
177 ToscaPropertyType isPrimitiveToscaType = ToscaPropertyType.isValidType(dataTypeName);
178 return isPrimitiveToscaType != null && isPrimitiveToscaType.isAbstract();
181 private boolean isScalarType(DataTypeDefinition dataTypeDef) {
182 boolean isScalar = false;
183 DataTypeDefinition dataType = dataTypeDef;
184 while (dataType != null) {
185 String name = dataType.getName();
186 if (ToscaPropertyType.isScalarType(name)) {
190 dataType = dataType.getDerivedFrom();
195 private DataTypeDefinition createDataType(String dataTypeName, Map<String, Object> toscaJson) {
196 DataTypeDefinition dataType = new DataTypeDefinition();
197 dataType.setName(dataTypeName);
198 if (toscaJson != null) {
200 commonImportManager.setField(toscaJson, TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName(), dataType::setDescription);
202 commonImportManager.setField(toscaJson, TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName(), dataType::setDerivedFromName);
204 CommonImportManager.setProperties(toscaJson, dataType::setProperties);