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.lang3.tuple.ImmutablePair;
29 import org.openecomp.sdc.be.config.BeEcompErrorManager;
30 import org.openecomp.sdc.be.dao.api.ActionStatus;
31 import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
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.DataTypeDefinition;
36 import org.openecomp.sdc.be.model.Resource;
37 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
38 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
39 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
40 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
41 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
42 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
43 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
44 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
45 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
46 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
47 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
48 import org.openecomp.sdc.common.log.wrappers.Logger;
49 import org.openecomp.sdc.exception.ResponseFormat;
50 import org.springframework.beans.factory.annotation.Autowired;
51 import org.springframework.stereotype.Component;
54 * This class holds the business logic relevant for attributes manipulation.
59 @Component("attributeBusinessLogic")
60 public class AttributeBusinessLogic extends BaseBusinessLogic {
62 private static final String CREATE_ATTRIBUTE = "CreateAttribute";
63 private static final String UPDATE_ATTRIBUTE = "UpdateAttribute";
64 private static final String DELETE_ATTRIBUTE = "DeleteAttribute";
66 private static final Logger log = Logger.getLogger(AttributeBusinessLogic.class);
67 private static final String FAILED_TO_LOCK_COMPONENT_ERROR = "Failed to lock component {}. Error - {}";
70 public AttributeBusinessLogic(IElementOperation elementDao,
71 IGroupOperation groupOperation,
72 IGroupInstanceOperation groupInstanceOperation,
73 IGroupTypeOperation groupTypeOperation,
74 InterfaceOperation interfaceOperation,
75 InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
76 ArtifactsOperations artifactToscaOperation) {
77 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation,
78 interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation);
82 * Created attribute on the resource with resourceId
85 * @param newAttributeDef
87 * @return AttributeDefinition if created successfully Or ResponseFormat
89 public Either<AttributeDataDefinition, ResponseFormat> createAttribute(String resourceId, AttributeDataDefinition newAttributeDef, String userId) {
90 Either<AttributeDataDefinition, ResponseFormat> result = null;
91 validateUserExists(userId);
93 StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
94 if (lockResult != StorageOperationStatus.OK) {
95 BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
96 log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
97 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
101 // Get the resource from DB
102 Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId);
103 if (status.isRight()) {
104 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
106 Resource resource = status.left().value();
108 // verify that resource is checked-out and the user is the last updater
109 if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
110 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
113 // verify attribute does not exist in resource
114 if (isAttributeExist(resource.getAttributes(), resourceId, newAttributeDef.getName())) {
115 return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_ALREADY_EXIST, newAttributeDef.getName()));
117 Map<String, DataTypeDefinition> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
118 // validate property default values
119 Either<Boolean, ResponseFormat> defaultValuesValidation = validateAttributeDefaultValue(newAttributeDef, eitherAllDataTypes);
120 if (defaultValuesValidation.isRight()) {
121 return Either.right(defaultValuesValidation.right().value());
124 handleAttributeDefaultValue(newAttributeDef, eitherAllDataTypes);
126 // add the new attribute to resource on graph
127 // need to get StorageOperationStatus and convert to ActionStatus from
129 Either<AttributeDataDefinition, StorageOperationStatus> either = toscaOperationFacade.addAttributeOfResource(resource, newAttributeDef);
130 if (either.isRight()) {
131 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName()));
134 result = Either.left(either.left().value());
138 commitOrRollback(result);
139 graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
143 private Either<Boolean, ResponseFormat> validateAttributeDefaultValue(final AttributeDataDefinition attributeDefinition,
144 final Map<String, DataTypeDefinition> dataTypes) {
147 if (!attributeOperation.isAttributeTypeValid(attributeDefinition)) {
148 log.info("Invalid type for attribute '{}' type '{}'", attributeDefinition.getName(), attributeDefinition.getType());
149 final ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE, attributeDefinition
150 .getType(), attributeDefinition.getName());
151 return Either.right(responseFormat);
153 String type = attributeDefinition.getType();
154 String innerType = null;
155 if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) {
156 final ImmutablePair<String, Boolean> propertyInnerTypeValid = attributeOperation.isAttributeInnerTypeValid(
157 attributeDefinition, dataTypes);
158 innerType = propertyInnerTypeValid.getLeft();
159 if (!propertyInnerTypeValid.getRight()) {
160 log.info("Invalid inner type for attribute '{}' type '{}', dataTypeCount '{}'",
161 attributeDefinition.getName(), attributeDefinition.getType(), dataTypes.size());
162 final ResponseFormat responseFormat = componentsUtils
163 .getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE, innerType, attributeDefinition.getName());
164 return Either.right(responseFormat);
167 if (!attributeOperation.isAttributeDefaultValueValid(attributeDefinition, dataTypes)) {
168 log.info("Invalid default value for attribute '{}' type '{}'", attributeDefinition.getName(),
169 attributeDefinition.getType());
170 ResponseFormat responseFormat;
171 if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) {
172 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE,
173 attributeDefinition.getName(), type, innerType,
174 (String) attributeDefinition.get_default());
176 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEFAULT_VALUE,
177 attributeDefinition.getName(), type, (String) attributeDefinition.get_default());
179 return Either.right(responseFormat);
182 return Either.left(true);
185 private void handleAttributeDefaultValue(final AttributeDataDefinition newAttributeDefinition,
186 final Map<String, DataTypeDefinition> dataTypes) {
187 final ToscaPropertyType type = ToscaPropertyType.isValidType(newAttributeDefinition.getType());
188 final PropertyValueConverter converter = type.getConverter();
190 String innerType = null;
191 final SchemaDefinition schema = newAttributeDefinition.getSchema();
192 if (schema != null) {
193 final PropertyDataDefinition prop = schema.getProperty();
194 if (schema.getProperty() != null) {
195 innerType = prop.getType();
198 if (newAttributeDefinition.get_default() != null) {
199 newAttributeDefinition.set_default(converter
200 .convert((String) newAttributeDefinition.get_default(), innerType, dataTypes));
204 private boolean isAttributeExist(List<AttributeDataDefinition> attributes, String resourceUid, String propertyName) {
205 boolean isExist = false;
206 if (attributes != null) {
207 isExist = attributes.stream().anyMatch(p -> Objects.equals(p.getName(), propertyName) && Objects.equals(p.getOwnerId(), resourceUid));
219 public Either<AttributeDataDefinition, ResponseFormat> getAttribute(String resourceId, String attributeId, String userId) {
221 validateUserExists(userId);
223 // Get the resource from DB
224 Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId);
225 if (status.isRight()) {
226 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
228 Resource resource = status.left().value();
230 List<AttributeDataDefinition> attributes = resource.getAttributes();
231 if (attributes == null) {
232 return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, ""));
234 // verify attribute exist in resource
235 Optional<AttributeDataDefinition> optionalAtt = attributes.stream().filter(att ->
236 att.getUniqueId().equals(attributeId)).findAny();
237 return optionalAtt.<Either<AttributeDataDefinition, ResponseFormat>>map(Either::left).orElseGet(() ->
238 Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, "")));
243 * Updates Attribute on resource
251 public Either<AttributeDataDefinition, ResponseFormat> updateAttribute(String resourceId, String attributeId, AttributeDataDefinition newAttDef, String userId) {
252 Either<AttributeDataDefinition, ResponseFormat> result = null;
254 StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
255 if (lockResult != StorageOperationStatus.OK) {
256 BeEcompErrorManager.getInstance().logBeFailedLockObjectError(UPDATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
257 log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
258 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
261 // Get the resource from DB
262 Either<Resource, StorageOperationStatus> eitherResource = toscaOperationFacade.getToscaElement(resourceId);
263 if (eitherResource.isRight()) {
264 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
266 Resource resource = eitherResource.left().value();
268 // verify that resource is checked-out and the user is the last updater
269 if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
270 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
273 // verify attribute exist in resource
274 Either<AttributeDataDefinition, ResponseFormat> eitherAttribute = getAttribute(resourceId, attributeId, userId);
275 if (eitherAttribute.isRight()) {
276 return Either.right(eitherAttribute.right().value());
278 Map<String, DataTypeDefinition> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
280 // validate attribute default values
281 Either<Boolean, ResponseFormat> defaultValuesValidation = validateAttributeDefaultValue(newAttDef, eitherAllDataTypes);
282 if (defaultValuesValidation.isRight()) {
283 return Either.right(defaultValuesValidation.right().value());
286 // add the new property to resource on graph
287 StorageOperationStatus validateAndUpdateAttribute = attributeOperation.validateAndUpdateAttribute(newAttDef, eitherAllDataTypes);
288 if (validateAndUpdateAttribute != StorageOperationStatus.OK) {
289 log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId, validateAndUpdateAttribute);
290 result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(validateAndUpdateAttribute), resource.getName()));
293 Either<AttributeDataDefinition, StorageOperationStatus> eitherAttUpdate = toscaOperationFacade.updateAttributeOfResource(resource, newAttDef);
295 if (eitherAttUpdate.isRight()) {
296 log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId, eitherAttUpdate.right().value());
297 result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherAttUpdate.right().value()), resource.getName()));
301 result = Either.left(eitherAttUpdate.left().value());
304 commitOrRollback(result);
305 graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
311 * Deletes Attribute on resource
318 public Either<AttributeDataDefinition, ResponseFormat> deleteAttribute(String resourceId, String attributeId, String userId) {
320 Either<AttributeDataDefinition, ResponseFormat> result = null;
322 validateUserExists(userId);
324 StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
325 if (lockResult != StorageOperationStatus.OK) {
326 BeEcompErrorManager.getInstance().logBeFailedLockObjectError(DELETE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
327 log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
328 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
332 // Get the resource from DB
333 Either<Resource, StorageOperationStatus> eitherResource = toscaOperationFacade.getToscaElement(resourceId);
334 if (eitherResource.isRight()) {
335 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
337 Resource resource = eitherResource.left().value();
339 // verify that resource is checked-out and the user is the last updater
340 if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
341 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
344 // verify attribute exist in resource
345 Either<AttributeDataDefinition, ResponseFormat> eitherAttributeExist = getAttribute(resourceId, attributeId, userId);
346 if (eitherAttributeExist.isRight()) {
347 return Either.right(eitherAttributeExist.right().value());
349 String attributeName = eitherAttributeExist.left().value().getName();
351 // delete attribute of resource from graph
352 StorageOperationStatus eitherAttributeDelete = toscaOperationFacade.deleteAttributeOfResource(resource, attributeName);
353 if (eitherAttributeDelete != StorageOperationStatus.OK) {
354 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(eitherAttributeDelete), resource.getName()));
358 result = Either.left(eitherAttributeExist.left().value());
361 commitOrRollback(result);
362 graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);