Support for defining attributes on a node_type
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / AttributeBusinessLogic.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.openecomp.sdc.be.components.impl;
22
23 import fj.data.Either;
24 import org.openecomp.sdc.be.config.BeEcompErrorManager;
25 import org.openecomp.sdc.be.dao.api.ActionStatus;
26 import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
27 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
28 import org.openecomp.sdc.be.model.AttributeDefinition;
29 import org.openecomp.sdc.be.model.DataTypeDefinition;
30 import org.openecomp.sdc.be.model.Resource;
31 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
32 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
33 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
34 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
35 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
36 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
37 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
38 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
39 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
40 import org.openecomp.sdc.common.log.wrappers.Logger;
41 import org.openecomp.sdc.exception.ResponseFormat;
42 import org.springframework.beans.factory.annotation.Autowired;
43 import org.springframework.stereotype.Component;
44
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Objects;
48 import java.util.Optional;
49
50 /**
51  * This class holds the business logic relevant for attributes manipulation.
52  * 
53  * @author mshitrit
54  *
55  */
56 @Component("attributeBusinessLogic")
57 public class AttributeBusinessLogic extends BaseBusinessLogic {
58
59     private static final String CREATE_ATTRIBUTE = "CreateAttribute";
60     private static final String UPDATE_ATTRIBUTE = "UpdateAttribute";
61     private static final String DELETE_ATTRIBUTE = "DeleteAttribute";
62
63     private static final Logger log = Logger.getLogger(AttributeBusinessLogic.class);
64     private static final String FAILED_TO_LOCK_COMPONENT_ERROR = "Failed to lock component {}. Error - {}";
65
66     @Autowired
67     public AttributeBusinessLogic(IElementOperation elementDao,
68         IGroupOperation groupOperation,
69         IGroupInstanceOperation groupInstanceOperation,
70         IGroupTypeOperation groupTypeOperation,
71         InterfaceOperation interfaceOperation,
72         InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
73         ArtifactsOperations artifactToscaOperation) {
74         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation,
75             interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation);
76     }
77
78     /**
79      * Created attribute on the resource with resourceId
80      *
81      * @param resourceId
82      * @param newAttributeDef
83      * @param userId
84      * @return AttributeDefinition if created successfully Or ResponseFormat
85      */
86     public Either<AttributeDataDefinition, ResponseFormat> createAttribute(String resourceId, AttributeDataDefinition newAttributeDef, String userId) {
87         Either<AttributeDataDefinition, ResponseFormat> result = null;
88         validateUserExists(userId);
89
90         StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
91         if (lockResult != StorageOperationStatus.OK) {
92             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
93             log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
94             return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
95         }
96
97         try {
98             // Get the resource from DB
99             Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId);
100             if (status.isRight()) {
101                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
102             }
103             Resource resource = status.left().value();
104
105             // verify that resource is checked-out and the user is the last updater
106             if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
107                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
108             }
109
110             // verify attribute does not exist in resource
111             if (isAttributeExist(resource.getAttributes(), resourceId, newAttributeDef.getName())) {
112                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_ALREADY_EXIST, newAttributeDef.getName()));
113             }
114             Map<String, DataTypeDefinition> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
115             // validate property default values
116             Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue((AttributeDefinition)newAttributeDef, eitherAllDataTypes);
117             if (defaultValuesValidation.isRight()) {
118                 return Either.right(defaultValuesValidation.right().value());
119             }
120
121             handleDefaultValue((AttributeDefinition)newAttributeDef, eitherAllDataTypes);
122
123             // add the new attribute to resource on graph
124             // need to get StorageOpaerationStatus and convert to ActionStatus from
125             // componentsUtils
126             Either<AttributeDataDefinition, StorageOperationStatus> either = toscaOperationFacade.addAttributeOfResource(resource, newAttributeDef);
127             if (either.isRight()) {
128                 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName()));
129                 return result;
130             }
131             result = Either.left(either.left().value());
132
133             return result;
134         } finally {
135             commitOrRollback(result);
136             graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
137         }
138
139     }
140
141     private boolean isAttributeExist(List<AttributeDataDefinition> attributes, String resourceUid, String propertyName) {
142         boolean isExist = false;
143         if (attributes != null) {
144             isExist = attributes.stream().anyMatch(p -> Objects.equals(p.getName(), propertyName) && Objects.equals(p.getParentUniqueId(), resourceUid));
145         }
146         return isExist;
147
148     }
149
150     /**
151      * @param resourceId
152      * @param attributeId
153      * @param userId
154      * @return
155      */
156     public Either<AttributeDataDefinition, ResponseFormat> getAttribute(String resourceId, String attributeId, String userId) {
157
158         validateUserExists(userId);
159
160         // Get the resource from DB
161         Either<Resource, StorageOperationStatus> status = toscaOperationFacade.getToscaElement(resourceId);
162         if (status.isRight()) {
163             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
164         }
165         Resource resource = status.left().value();
166
167         List<AttributeDataDefinition> attributes = resource.getAttributes();
168         if (attributes == null) {
169             return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, ""));
170         } else {
171             // verify attribute exist in resource
172             Optional<AttributeDataDefinition> optionalAtt = attributes.stream().filter(att -> att.getUniqueId().equals(attributeId) && resourceId.equals(att.getParentUniqueId())).findAny();
173             return optionalAtt.<Either<AttributeDataDefinition, ResponseFormat>>map(Either::left).orElseGet(() -> Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, "")));
174         }
175     }
176
177     /**
178      * Updates Attribute on resource
179      *
180      * @param resourceId
181      * @param attributeId
182      * @param newAttDef
183      * @param userId
184      * @return
185      */
186     public Either<AttributeDataDefinition, ResponseFormat> updateAttribute(String resourceId, String attributeId, AttributeDataDefinition newAttDef, String userId) {
187         Either<AttributeDataDefinition, ResponseFormat> result = null;
188
189         StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
190         if (lockResult != StorageOperationStatus.OK) {
191             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(UPDATE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
192             log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
193             return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
194         }
195         try {
196             // Get the resource from DB
197             Either<Resource, StorageOperationStatus> eitherResource = toscaOperationFacade.getToscaElement(resourceId);
198             if (eitherResource.isRight()) {
199                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
200             }
201             Resource resource = eitherResource.left().value();
202
203             // verify that resource is checked-out and the user is the last updater
204             if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
205                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
206             }
207
208             // verify attribute exist in resource
209             Either<AttributeDataDefinition, ResponseFormat> eitherAttribute = getAttribute(resourceId, attributeId, userId);
210             if (eitherAttribute.isRight()) {
211                 return Either.right(eitherAttribute.right().value());
212             }
213             Map<String, DataTypeDefinition> eitherAllDataTypes = getAllDataTypes(applicationDataTypeCache);
214
215             // validate attribute default values
216             Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue((AttributeDefinition)newAttDef, eitherAllDataTypes);
217             if (defaultValuesValidation.isRight()) {
218                 return Either.right(defaultValuesValidation.right().value());
219             }
220
221             // add the new property to resource on graph
222             StorageOperationStatus validateAndUpdateAttribute = propertyOperation.validateAndUpdateProperty((AttributeDefinition)newAttDef, eitherAllDataTypes);
223             if (validateAndUpdateAttribute != StorageOperationStatus.OK) {
224                 log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId, validateAndUpdateAttribute);
225                 result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(validateAndUpdateAttribute), resource.getName()));
226             }
227
228             Either<AttributeDataDefinition, StorageOperationStatus> eitherAttUpdate = toscaOperationFacade.updateAttributeOfResource(resource, newAttDef);
229
230             if (eitherAttUpdate.isRight()) {
231                 log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId, eitherAttUpdate.right().value());
232                 result = Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(eitherAttUpdate.right().value()), resource.getName()));
233                 return result;
234             }
235
236             result = Either.left(eitherAttUpdate.left().value());
237             return result;
238         } finally {
239             commitOrRollback(result);
240             graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
241         }
242
243     }
244
245     /**
246      * Deletes Attribute on resource
247      *
248      * @param resourceId
249      * @param attributeId
250      * @param userId
251      * @return
252      */
253     public Either<AttributeDataDefinition, ResponseFormat> deleteAttribute(String resourceId, String attributeId, String userId) {
254
255         Either<AttributeDataDefinition, ResponseFormat> result = null;
256
257         validateUserExists(userId);
258
259         StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource);
260         if (lockResult != StorageOperationStatus.OK) {
261             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(DELETE_ATTRIBUTE, NodeTypeEnum.Resource.name().toLowerCase(), resourceId);
262             log.info(FAILED_TO_LOCK_COMPONENT_ERROR, resourceId, lockResult);
263             return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
264         }
265
266         try {
267             // Get the resource from DB
268             Either<Resource, StorageOperationStatus> eitherResource = toscaOperationFacade.getToscaElement(resourceId);
269             if (eitherResource.isRight()) {
270                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
271             }
272             Resource resource = eitherResource.left().value();
273
274             // verify that resource is checked-out and the user is the last updater
275             if (!ComponentValidationUtils.canWorkOnResource(resource, userId)) {
276                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
277             }
278
279             // verify attribute exist in resource
280             Either<AttributeDataDefinition, ResponseFormat> eitherAttributeExist = getAttribute(resourceId, attributeId, userId);
281             if (eitherAttributeExist.isRight()) {
282                 return Either.right(eitherAttributeExist.right().value());
283             }
284             String attributeName = eitherAttributeExist.left().value().getName();
285
286             // delete attribute of resource from graph
287             StorageOperationStatus eitherAttributeDelete = toscaOperationFacade.deleteAttributeOfResource(resource, attributeName);
288             if (eitherAttributeDelete != StorageOperationStatus.OK) {
289                 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(eitherAttributeDelete), resource.getName()));
290                 return result;
291             }
292
293             result = Either.left(eitherAttributeExist.left().value());
294             return result;
295         } finally {
296             commitOrRollback(result);
297             graphLockOperation.unlockComponent(resourceId, NodeTypeEnum.Resource);
298         }
299     }
300 }