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=========================================================
21 package org.openecomp.sdc.be.components.impl;
23 import fj.data.Either;
24 import java.util.List;
26 import java.util.Objects;
27 import java.util.Optional;
28 import org.apache.commons.collections.MapUtils;
29 import org.apache.commons.lang3.tuple.ImmutablePair;
30 import org.openecomp.sdc.be.config.BeEcompErrorManager;
31 import org.openecomp.sdc.be.dao.api.ActionStatus;
32 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
33 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
34 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
35 import org.openecomp.sdc.be.model.AttributeDefinition;
36 import org.openecomp.sdc.be.model.Component;
37 import org.openecomp.sdc.be.model.ComponentParametersView;
38 import org.openecomp.sdc.be.model.DataTypeDefinition;
39 import org.openecomp.sdc.be.model.InterfaceDefinition;
40 import org.openecomp.sdc.be.model.Resource;
41 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
42 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
43 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
44 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
45 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
46 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
47 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
48 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
49 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
50 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
51 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
52 import org.openecomp.sdc.common.log.wrappers.Logger;
53 import org.openecomp.sdc.exception.ResponseFormat;
54 import org.springframework.beans.factory.annotation.Autowired;
57 * This class holds the business logic relevant for attributes manipulation.
61 @org.springframework.stereotype.Component("attributeBusinessLogic")
62 public class AttributeBusinessLogic extends BaseBusinessLogic {
64 private static final String CREATE_ATTRIBUTE = "CreateAttribute";
65 private static final String UPDATE_ATTRIBUTE = "UpdateAttribute";
66 private static final String DELETE_ATTRIBUTE = "DeleteAttribute";
68 private static final Logger log = Logger.getLogger(AttributeBusinessLogic.class);
69 private static final String FAILED_TO_LOCK_COMPONENT_ERROR = "Failed to lock component {}. Error - {}";
72 public AttributeBusinessLogic(IElementOperation elementDao,
73 IGroupOperation groupOperation,
74 IGroupInstanceOperation groupInstanceOperation,
75 IGroupTypeOperation groupTypeOperation,
76 InterfaceOperation interfaceOperation,
77 InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
78 ArtifactsOperations artifactToscaOperation) {
79 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation,
80 interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation);
84 * Created attribute on the resource with resourceId
87 * @param newAttributeDef
89 * @return AttributeDefinition if created successfully Or ResponseFormat
91 public Either<AttributeDefinition, ResponseFormat> createAttribute(String resourceId,
92 AttributeDefinition newAttributeDef,
94 Either<AttributeDefinition, ResponseFormat> result = null;
95 validateUserExists(userId);
97 StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
98 if (lockResult != StorageOperationStatus.OK) {
99 BeEcompErrorManager.getInstance()
100 .logBeFailedLockObjectError(CREATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
101 log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
102 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
106 // Get the resource from DB
107 Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId);
108 if (status.isRight()) {
109 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
111 Resource resource = status.left().value();
113 // verify that resource is checked-out and the user is the last updater
114 if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
115 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
118 // verify attribute does not exist in resource
119 if (isAttributeExist(resource.getAttributes(), resourceId, newAttributeDef.getName())) {
121 componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_ALREADY_EXIST, newAttributeDef.getName()));
123 Map<String, DataTypeDefinition> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
124 // validate property default values
125 Either<Boolean, ResponseFormat> defaultValuesValidation = validateAttributeDefaultValue(newAttributeDef,
127 if (defaultValuesValidation.isRight()) {
128 return Either.right(defaultValuesValidation.right().value());
131 handleAttributeDefaultValue(newAttributeDef, eitherAllDataTypes);
133 // add the new attribute to resource on graph
134 // need to get StorageOperationStatus and convert to ActionStatus from
136 Either<AttributeDefinition, StorageOperationStatus> either = toscaOperationFacade
137 .addAttributeOfResource(resource, newAttributeDef);
138 if (either.isRight()) {
139 result = Either.right(componentsUtils
140 .getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()),
141 resource.getName()));
144 result = Either.left(either.left().value());
148 commitOrRollback(result);
149 graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
153 private Either<Boolean, ResponseFormat> validateAttributeDefaultValue(final AttributeDefinition attributeDefinition,
154 final Map<String, DataTypeDefinition> dataTypes) {
156 if (!attributeOperation.isAttributeTypeValid(attributeDefinition)) {
157 log.info("Invalid type for attribute '{}' type '{}'", attributeDefinition.getName(),
158 attributeDefinition.getType());
159 final ResponseFormat responseFormat = componentsUtils
160 .getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE, attributeDefinition
161 .getType(), attributeDefinition.getName());
162 return Either.right(responseFormat);
164 String type = attributeDefinition.getType();
165 String innerType = null;
166 if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) {
167 final ImmutablePair<String, Boolean> propertyInnerTypeValid = attributeOperation.isAttributeInnerTypeValid(
168 attributeDefinition, dataTypes);
169 innerType = propertyInnerTypeValid.getLeft();
170 if (!Boolean.TRUE.equals(propertyInnerTypeValid.getRight())) {
171 log.info("Invalid inner type for attribute '{}' type '{}', dataTypeCount '{}'",
172 attributeDefinition.getName(), attributeDefinition.getType(), dataTypes.size());
173 final ResponseFormat responseFormat = componentsUtils
174 .getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE, innerType,
175 attributeDefinition.getName());
176 return Either.right(responseFormat);
179 if (!attributeOperation.isAttributeDefaultValueValid(attributeDefinition, dataTypes)) {
180 log.info("Invalid default value for attribute '{}' type '{}'", attributeDefinition.getName(),
181 attributeDefinition.getType());
182 ResponseFormat responseFormat;
183 if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) {
184 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE,
185 attributeDefinition.getName(), type, innerType,
186 (String) attributeDefinition.get_default());
188 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEFAULT_VALUE,
189 attributeDefinition.getName(), type, (String) attributeDefinition.get_default());
191 return Either.right(responseFormat);
194 return Either.left(true);
197 private void handleAttributeDefaultValue(final AttributeDefinition newAttributeDefinition,
198 final Map<String, DataTypeDefinition> dataTypes) {
199 final ToscaPropertyType type = ToscaPropertyType.isValidType(newAttributeDefinition.getType());
200 final PropertyValueConverter converter = type.getConverter();
202 String innerType = null;
203 final SchemaDefinition schema = newAttributeDefinition.getSchema();
204 if (schema != null) {
205 final PropertyDataDefinition prop = schema.getProperty();
206 if (schema.getProperty() != null) {
207 innerType = prop.getType();
210 if (newAttributeDefinition.get_default() != null) {
211 newAttributeDefinition.set_default(converter
212 .convert((String) newAttributeDefinition.get_default(), innerType, dataTypes));
216 private boolean isAttributeExist(List<AttributeDefinition> attributes, String resourceUid, String propertyName) {
217 boolean isExist = false;
218 if (attributes != null) {
219 isExist = attributes.stream().anyMatch(
220 p -> Objects.equals(p.getName(), propertyName) && Objects.equals(p.getOwnerId(), resourceUid));
232 public Either<AttributeDefinition, ResponseFormat> getAttribute(String resourceId, String attributeId,
235 validateUserExists(userId);
237 // Get the resource from DB
238 Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId);
239 if (status.isRight()) {
240 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
242 Resource resource = status.left().value();
244 List<AttributeDefinition> attributes = resource.getAttributes();
245 if (attributes == null) {
246 return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, ""));
248 // verify attribute exist in resource
249 Optional<AttributeDefinition> optionalAtt = attributes.stream().filter(att ->
250 att.getUniqueId().equals(attributeId)).findAny();
251 return optionalAtt.<Either<AttributeDefinition, ResponseFormat>>map(Either::left).orElseGet(() ->
252 Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, "")));
257 * Updates Attribute on resource
265 public Either<AttributeDefinition, ResponseFormat> updateAttribute(String resourceId, String attributeId,
266 AttributeDefinition newAttDef, String userId) {
267 Either<AttributeDefinition, ResponseFormat> result = null;
269 StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
270 if (lockResult != StorageOperationStatus.OK) {
271 BeEcompErrorManager.getInstance()
272 .logBeFailedLockObjectError(UPDATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
273 log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
274 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
277 // Get the resource from DB
278 Either<Resource, StorageOperationStatus> eitherResource = toscaOperationFacade.getToscaElement(resourceId);
279 if (eitherResource.isRight()) {
280 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
282 Resource resource = eitherResource.left().value();
284 // verify that resource is checked-out and the user is the last updater
285 if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
286 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
289 // verify attribute exist in resource
290 Either<AttributeDefinition, ResponseFormat> eitherAttribute = getAttribute(resourceId, attributeId, userId);
291 if (eitherAttribute.isRight()) {
292 return Either.right(eitherAttribute.right().value());
294 Map<String, DataTypeDefinition> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
296 // validate attribute default values
297 Either<Boolean, ResponseFormat> defaultValuesValidation = validateAttributeDefaultValue(newAttDef,
299 if (defaultValuesValidation.isRight()) {
300 return Either.right(defaultValuesValidation.right().value());
303 // add the new property to resource on graph
304 StorageOperationStatus validateAndUpdateAttribute = attributeOperation
305 .validateAndUpdateAttribute(newAttDef, eitherAllDataTypes);
306 if (validateAndUpdateAttribute != StorageOperationStatus.OK) {
307 log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId,
308 validateAndUpdateAttribute);
309 result = Either.right(componentsUtils
310 .getResponseFormatByResource(componentsUtils.convertFromStorageResponse(validateAndUpdateAttribute),
311 resource.getName()));
314 Either<AttributeDefinition, StorageOperationStatus> eitherAttUpdate = toscaOperationFacade
315 .updateAttributeOfResource(resource, newAttDef);
317 if (eitherAttUpdate.isRight()) {
318 log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId,
319 eitherAttUpdate.right().value());
320 result = Either.right(componentsUtils.getResponseFormatByResource(
321 componentsUtils.convertFromStorageResponse(eitherAttUpdate.right().value()), resource.getName()));
325 result = Either.left(eitherAttUpdate.left().value());
328 commitOrRollback(result);
329 graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
335 * Deletes Attribute on resource
342 public Either<AttributeDefinition, ResponseFormat> deleteAttribute(String resourceId, String attributeId,
345 Either<AttributeDefinition, ResponseFormat> result = null;
347 validateUserExists(userId);
349 StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
350 if (lockResult != StorageOperationStatus.OK) {
351 BeEcompErrorManager.getInstance()
352 .logBeFailedLockObjectError(DELETE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
353 log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
354 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
358 // Get the resource from DB
359 Either<Resource, StorageOperationStatus> eitherResource = toscaOperationFacade.getToscaElement(resourceId);
360 if (eitherResource.isRight()) {
361 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
363 Resource resource = eitherResource.left().value();
365 // verify that resource is checked-out and the user is the last updater
366 if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
367 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
370 // verify attribute exist in resource
371 Either<AttributeDefinition, ResponseFormat> eitherAttributeExist = getAttribute(resourceId, attributeId,
373 if (eitherAttributeExist.isRight()) {
374 return Either.right(eitherAttributeExist.right().value());
376 String attributeName = eitherAttributeExist.left().value().getName();
378 // delete attribute of resource from graph
379 StorageOperationStatus eitherAttributeDelete = toscaOperationFacade
380 .deleteAttributeOfResource(resource, attributeName);
381 if (eitherAttributeDelete != StorageOperationStatus.OK) {
382 result = Either.right(componentsUtils
383 .getResponseFormat(componentsUtils.convertFromStorageResponse(eitherAttributeDelete),
384 resource.getName()));
388 result = Either.left(eitherAttributeExist.left().value());
391 commitOrRollback(result);
392 graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
396 public Either<List<AttributeDefinition>, ResponseFormat> getAttributesList(final String componentId,
397 final String userId) {
398 validateUserExists(userId);
400 // Get the resource from DB
401 final ComponentParametersView filter = new ComponentParametersView(true);
402 filter.setIgnoreAttributes(false);
403 final Either<Component, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(componentId, filter);
404 if (status.isRight()) {
405 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
408 return Either.left(status.left().value().getAttributes());
411 public boolean isAttributeUsedByOperation(Component component,
412 AttributeDefinition propertyDefinitionEntry) {
413 // TODO - do we need this one
416 // // Component's own interfaces
417 // Map<String, InterfaceDefinition> interfaces = component.getInterfaces();
418 // if(MapUtils.isNotEmpty(interfaces)){
419 // for(Map.Entry<String, InterfaceDefinition> interfaceEntry : interfaces.entrySet()) {
420 // if (isPropertyExistInOperationInterface(propertyDefinitionEntry, interfaceEntry.getValue())) {
426 // // Component's child's component interfaces
427 // if(isPropertyUsedInCIInterfaces(component.getComponentInstancesInterfaces(), propertyDefinitionEntry)){
431 // // Component's parent's component interfaces
432 // Either<List<Component>, StorageOperationStatus> componentList = toscaOperationFacade.getParentComponents(component.getUniqueId());
433 // if(componentList.isLeft()){
434 // for (Component parentComponent : componentList.left().value()) {
435 // if(isPropertyUsedInCIInterfaces(parentComponent.getComponentInstancesInterfaces(), propertyDefinitionEntry)){