re base code
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / PolicyBusinessLogic.java
1 package org.openecomp.sdc.be.components.impl;
2
3 import fj.data.Either;
4 import org.apache.commons.collections.CollectionUtils;
5 import org.openecomp.sdc.be.dao.api.ActionStatus;
6 import org.openecomp.sdc.be.datatypes.elements.PolicyDataDefinition;
7 import org.openecomp.sdc.be.datatypes.elements.PolicyTargetType;
8 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
9 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
10 import org.openecomp.sdc.be.model.*;
11 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
12 import org.openecomp.sdc.common.datastructure.Wrapper;
13 import org.openecomp.sdc.common.log.wrappers.Logger;
14 import org.openecomp.sdc.exception.ResponseFormat;
15
16 import java.util.Arrays;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.function.Function;
21 import java.util.stream.Collectors;
22
23 import static java.util.stream.Collectors.toMap;
24 import static org.openecomp.sdc.be.components.validation.PolicyUtils.*;
25
26 /**
27  * Provides specified business logic to create, retrieve, update, delete a policy
28  */
29 @org.springframework.stereotype.Component("policyBusinessLogic")
30 public class PolicyBusinessLogic extends BaseBusinessLogic {
31
32     private static final String FAILED_TO_VALIDATE_COMPONENT = "#{} - failed to validate the component {} before policy processing. ";
33     private static final Logger log = Logger.getLogger(PolicyBusinessLogic.class);
34
35     /**
36      * Adds the newly created policy of the specified type to the component
37      *
38      * @param componentType  the type of the component
39      * @param componentId    the id of the component which the policy resides under
40      * @param policyTypeName the name of the policy type
41      * @param userId         the user creator id
42      * @param shouldLock     the flag defining if the component should be locked
43      * @return a policy or an error in a response format
44      */
45
46     public Either<PolicyDefinition, ResponseFormat> createPolicy(ComponentTypeEnum componentType, String componentId, String policyTypeName, String userId, boolean shouldLock) {
47
48         Either<PolicyDefinition, ResponseFormat> result = null;
49         log.trace("#createPolicy - starting to create policy of the type {} on the component {}. ", policyTypeName, componentId);
50         Wrapper<Component> component = new Wrapper<>();
51         try {
52             result = validateAndLockComponentAndUserBeforeWriteOperation(componentType, componentId, userId, shouldLock)
53                     .left()
54                     .bind(c -> {
55                         component.setInnerElement(c);
56                         return createPolicy(policyTypeName, c);
57                     });
58         } catch (Exception e) {
59             log.error("#createPolicy - the exception  occurred upon creation of a policy of the type {} for the component {}: ", policyTypeName, componentId, e);
60             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
61         } finally {
62
63             unlockComponent(shouldLock, result, component);
64         }
65         return result;
66     }
67
68     /**
69      * Retrieves the policy of the component by UniqueId
70      *
71      * @param componentType the type of the component
72      * @param componentId   the ID of the component
73      * @param policyId      the ID of the policy
74      * @param userId        the ID of the user
75      * @return              either policy or error response
76      */
77     public Either<PolicyDefinition, ResponseFormat> getPolicy(ComponentTypeEnum componentType, String componentId, String policyId, String userId) {
78         Either<PolicyDefinition, ResponseFormat> result;
79         log.trace("#getPolicy - starting to retrieve the policy {} of the component {}. ", policyId, componentId);
80         try {
81             result = validateContainerComponentAndUserBeforeReadOperation(componentType, componentId, userId)
82                     .left()
83                     .bind(c -> getPolicyById(c, policyId));
84         } catch (Exception e) {
85             log.error("#getPolicy - the exception occurred upon retrieving the policy {} of the component {}: ", policyId, componentId, e);
86             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
87         }
88         return result;
89     }
90
91     /**
92      * Updates the policy of the component
93      *
94      * @param componentType the type of the component
95      * @param componentId   the id of the component which the policy resides under
96      * @param policy        the policy to update
97      * @param userId        the user modifier id
98      * @param shouldLock    the flag defining if the component should be locked
99      * @return a policy or an error in a response format
100      */
101     public Either<PolicyDefinition, ResponseFormat> updatePolicy(ComponentTypeEnum componentType, String componentId, PolicyDefinition policy, String userId, boolean shouldLock) {
102         Either<PolicyDefinition, ResponseFormat> result = null;
103         log.trace("#updatePolicy - starting to update the policy {} on the component {}. ", policy.getUniqueId(), componentId);
104         Wrapper<Component> component = new Wrapper<>();
105         try {
106             result = validateAndLockComponentAndUserBeforeWriteOperation(componentType, componentId, userId, shouldLock)
107                     .left()
108                     .bind(c -> {
109                         component.setInnerElement(c);
110                         return validateAndUpdatePolicy(c, policy);
111                     });
112         } catch (Exception e) {
113             log.error("#updatePolicy - the exception occurred upon update of a policy of the type {} for the component {}: ", policy.getUniqueId(), componentId, e);
114             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
115         } finally {
116             unlockComponent(shouldLock, result, component);
117         }
118         return result;
119     }
120
121     /**
122      * Deletes the policy from the component
123      *
124      * @param componentType the type of the component
125      * @param componentId   the id of the component which the policy resides under
126      * @param policyId      the id of the policy which its properties to return
127      * @param userId        the user modifier id
128      * @param shouldLock    the flag defining if the component should be locked
129      * @return a policy or an error in a response format
130      */
131     public Either<PolicyDefinition, ResponseFormat> deletePolicy(ComponentTypeEnum componentType, String componentId, String policyId, String userId, boolean shouldLock) {
132         Either<PolicyDefinition, ResponseFormat> result = null;
133         log.trace("#deletePolicy - starting to update the policy {} on the component {}. ", policyId, componentId);
134         Wrapper<Component> component = new Wrapper<>();
135         try {
136             result = validateAndLockComponentAndUserBeforeWriteOperation(componentType, componentId, userId, shouldLock)
137                     .left()
138                     .bind(c -> {
139                         component.setInnerElement(c);
140                         return deletePolicy(c, policyId);
141                     });
142         } catch (Exception e) {
143             log.error("#deletePolicy - the exception occurred upon update of a policy of the type {} for the component {}: ", policyId, componentId, e);
144         } finally {
145             unlockComponent(shouldLock, result, component);
146         }
147         return result;
148     }
149
150     public Either<PolicyDefinition, ResponseFormat> updatePolicyTargets(ComponentTypeEnum componentTypeEnum, String componentId, String policyId, Map<PolicyTargetType, List<String>> targets, String userId) {
151
152         Either<PolicyDefinition, ResponseFormat> result = null;
153         log.debug("updating the policy id {} targets with the components {}. ", policyId, componentId);
154         try {
155             //not right error response
156             result = validateAndLockComponentAndUserBeforeWriteOperation(componentTypeEnum, componentId, userId, true)
157                     .left()
158                     .bind(cmpt -> validateAndUpdatePolicyTargets(cmpt, policyId, targets));
159
160             return result;
161         } finally {
162
163             unlockComponentById(result, componentId);
164
165         }
166
167     }
168
169     private Either<PolicyDefinition, ResponseFormat> validateAndUpdatePolicyTargets(Component component, String policyId, Map<PolicyTargetType, List<String>> targets) {
170         return validateTargetsExistAndTypesCorrect(component.getUniqueId(), targets)
171                 .left()
172                 .bind(cmp ->updateTargets(component.getUniqueId(), component.getPolicyById(policyId), targets, policyId));
173
174     }
175
176     private Either<Component, ResponseFormat> validateTargetsExistAndTypesCorrect(String componentId, Map<PolicyTargetType, List<String>> targets) {
177         Either<Component, StorageOperationStatus> componentEither = toscaOperationFacade.getToscaFullElement(componentId);
178         if (componentEither.isRight()) {
179             return Either.right(componentsUtils.getResponseFormat(componentEither.right().value()));
180         }
181         Component parentComponent = componentEither.left().value();
182         return validateTargetExists(parentComponent, targets.entrySet());
183     }
184
185
186
187     private Either<Component, ResponseFormat> validateTargetExists(Component parentComponent, Set<Map.Entry<PolicyTargetType, List<String>>> entries) {
188         for(Map.Entry<PolicyTargetType, List<String>> entry : entries){
189             Either<Component, ResponseFormat> result = checkTargetNotExistOnComponentByType(parentComponent, entry);
190             if(result.isRight()){
191                 return result;
192             }
193         }
194         return Either.left(parentComponent);
195     }
196
197     private Either<Component, ResponseFormat> checkTargetNotExistOnComponentByType(Component parentComponent, Map.Entry<PolicyTargetType, List<String>> targetEntry) {
198
199         for(String id : targetEntry.getValue()){
200             if(checkNotPresenceInComponentByType(parentComponent, id, targetEntry.getKey().getName())){
201                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.POLICY_TARGET_DOES_NOT_EXIST, id));
202             }
203         }
204         return Either.left(parentComponent);
205     }
206
207     private boolean checkNotPresenceInComponentByType(Component parentComponent, String uniqueId, String type) {
208         if (type.equalsIgnoreCase(PolicyTargetType.GROUPS.getName()) && parentComponent.getGroups() != null) {
209             return !parentComponent.getGroupById(uniqueId).isPresent();
210         } else if (type.equalsIgnoreCase(PolicyTargetType.COMPONENT_INSTANCES.getName()) && parentComponent.getComponentInstances() != null) {
211             return !parentComponent.getComponentInstanceById(uniqueId).isPresent();
212         }
213         return true;
214     }
215
216     private PolicyDefinition setPolicyTargets(PolicyDefinition policyDefinition, Map<PolicyTargetType, List<String>> targets) {
217         policyDefinition.setTargets(targets);
218         return policyDefinition;
219     }
220
221
222     /**
223      * @param componentType the type of the component
224      * @param componentId   the id of the component which the policy resides under
225      * @param policyId      the id of the policy which its properties to return
226      * @param userId        the user id
227      * @return a list of policy properties or an error in a response format
228      */
229     public Either<List<PropertyDataDefinition>, ResponseFormat> getPolicyProperties(ComponentTypeEnum componentType, String componentId, String policyId, String userId) {
230         log.debug("#getPolicyProperties - fetching policy properties for component {} and policy {}", componentId, policyId);
231         try {
232             return validateContainerComponentAndUserBeforeReadOperation(componentType, componentId, userId)
233                     .left()
234                     .bind(cmpt -> getPolicyById(cmpt, policyId)).left().map(PolicyDataDefinition::getProperties);
235         } finally {
236             titanDao.commit();
237         }
238     }
239
240     /**
241      * Updates the policy properties of the component
242      *
243      * @param componentType the type of the component
244      * @param componentId   the id of the component which the policy resides under
245      * @param policyId      the id of the policy which its properties to return
246      * @param properties    a list of policy properties containing updated values
247      * @param userId        the user modifier id
248      * @param shouldLock    the flag defining if the component should be locked
249      * @return a list of policy properties or anerrorin a response format
250      */
251     public Either<List<PropertyDataDefinition>, ResponseFormat> updatePolicyProperties(ComponentTypeEnum componentType, String componentId, String policyId, PropertyDataDefinition[] properties, String userId, boolean shouldLock) {
252         Either<List<PropertyDataDefinition>, ResponseFormat> result = null;
253         log.trace("#updatePolicyProperties - starting to update properties of the policy {} on the component {}. ", policyId, componentId);
254         Wrapper<Component> component = new Wrapper<>();
255         try {
256             result = validateAndLockComponentAndUserBeforeWriteOperation(componentType, componentId, userId, shouldLock).left()
257                     .bind(c -> setComponentValidateUpdatePolicyProperties(policyId, properties, component, c));
258         } catch (Exception e) {
259             log.error("#updatePolicyProperties - the exception {} occurred upon update properties of the policy {} for the component {}: ", policyId, componentId, e);
260             result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
261         } finally {
262             if (shouldLock && !component.isEmpty()) {
263                 unlockComponent(result, component.getInnerElement());
264             }
265         }
266         return result;
267     }
268
269     private Either<List<PropertyDataDefinition>, ResponseFormat> setComponentValidateUpdatePolicyProperties(String policyId, PropertyDataDefinition[] properties, Wrapper<Component> component, Component c) {
270         component.setInnerElement(c);
271         Set<String> updatedPropertyNames = Arrays.stream(properties).map(PropertyDataDefinition::getName).collect(Collectors.toSet());
272         return validateAndUpdatePolicyProperties(c, policyId, properties)
273                 .left()
274                 .map(policyDefinition -> getFilteredProperties(policyDefinition.getProperties(), updatedPropertyNames));
275     }
276
277     private List<PropertyDataDefinition> getFilteredProperties(List<PropertyDataDefinition> all, Set<String> filtered) {
278         return all.stream().filter(pd -> filtered.contains(pd.getName())).collect(Collectors.toList());
279     }
280
281     private void unlockComponent(boolean shouldLock, Either<PolicyDefinition, ResponseFormat> result, Wrapper<Component> component) {
282         if (shouldLock && !component.isEmpty()) {
283             unlockComponent(result, component.getInnerElement());
284         }
285     }
286
287     private Either<PolicyDefinition, ResponseFormat> getPolicyById(Component component, String policyId) {
288         PolicyDefinition policyById = component.getPolicyById(policyId);
289         if (policyById == null) {
290             String cmptId = component.getUniqueId();
291             log.debug("#getPolicyById - policy with id {} does not exist on component with id {}", policyId, cmptId);
292             return Either.right(componentsUtils.getResponseFormat(ActionStatus.POLICY_NOT_FOUND_ON_CONTAINER, policyId, cmptId));
293         }
294         return Either.left(policyById);
295     }
296
297     private Either<PolicyDefinition, ResponseFormat> createPolicy(String policyTypeName, Component component) {
298         return validatePolicyTypeOnCreatePolicy(policyTypeName, component).left().bind(type -> addPolicyToComponent(type, component));
299     }
300
301     private Either<PolicyDefinition, ResponseFormat> addPolicyToComponent(PolicyTypeDefinition policyType, Component component) {
302         return toscaOperationFacade.associatePolicyToComponent(component.getUniqueId(), new PolicyDefinition(policyType), getNextPolicyCounter(component.getPolicies()))
303                 .either(Either::left, r -> Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(r))));
304     }
305
306     private Either<PolicyTypeDefinition, ResponseFormat> validatePolicyTypeOnCreatePolicy(String policyTypeName, Component component) {
307         return policyTypeOperation.getLatestPolicyTypeByType(policyTypeName)
308                 .either(l -> validatePolicyTypeNotExcluded(l, component), r -> Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(r))));
309     }
310
311     private Either<PolicyTypeDefinition, ResponseFormat> validatePolicyTypeNotExcluded(PolicyTypeDefinition policyType, Component component) {
312         if (getExcludedPolicyTypesByComponent(component).contains(policyType.getType())) {
313             return Either.right(componentsUtils.getResponseFormat(ActionStatus.EXCLUDED_POLICY_TYPE, policyType.getType(), getComponentOrResourceTypeName(component)));
314         }
315         return Either.left(policyType);
316     }
317
318     private String getComponentOrResourceTypeName(Component component) {
319         return component.getComponentType() == ComponentTypeEnum.SERVICE ? ComponentTypeEnum.SERVICE.name() : ((Resource) component).getResourceType().name();
320     }
321
322     private Either<Component, ResponseFormat> validateAndLockComponentAndUserBeforeWriteOperation(ComponentTypeEnum componentType, String componentId, String userId, boolean shouldLock) {
323         Wrapper<Component> component = new Wrapper<>();
324         return validateContainerComponentAndUserBeforeReadOperation(componentType, componentId, userId)
325                 .left()
326                 .bind(this::validateComponentIsTopologyTemplate)
327                 .left()
328                 .bind(c -> {
329                     component.setInnerElement(c);
330                     return validateCanWorkOnComponent(c, userId);
331                 })
332                 .left()
333                 .bind(l -> lockComponent(component.getInnerElement(), shouldLock, "policyWritingOperation"))
334                 .either(l -> Either.left(component.getInnerElement()), r -> {
335                     log.error(FAILED_TO_VALIDATE_COMPONENT, componentId);
336                     return Either.right(r);
337                 });
338     }
339
340     private Either<Component, ResponseFormat> validateComponentIsTopologyTemplate(Component component) {
341         if (!component.isTopologyTemplate()) {
342             log.error("#validateComponentIsTopologyTemplate - policy association to a component of Tosca type {} is not allowed. ", component.getToscaType());
343             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_CANNOT_CONTAIN_POLICIES, "#validateAndLockComponentAndUserBeforeWriteOperation", component.getUniqueId(), component.getToscaType()));
344         }
345         return Either.left(component);
346     }
347
348     private Either<Component, ResponseFormat> validateContainerComponentAndUserBeforeReadOperation(ComponentTypeEnum componentType, String componentId, String userId) {
349         Either<Component, ResponseFormat> result;
350         log.trace("#validateContainerComponentAndUserBeforeReadOperation - starting to validate the user {} before policy processing. ", userId);
351         validateUserExists(userId, "create Policy", false);
352         result = validateComponentExists(componentType, componentId);
353         if (result.isRight()) {
354             log.error(FAILED_TO_VALIDATE_COMPONENT, "#validateContainerComponentAndUserBeforeReadOperation", componentId);
355         }
356         return result;
357     }
358
359     private Either<Component, ResponseFormat> validateComponentExists(ComponentTypeEnum componentType, String componentId) {
360
361         ComponentParametersView filter = new ComponentParametersView(true);
362         filter.setIgnorePolicies(false);
363         filter.setIgnoreUsers(false);
364         filter.setIgnoreComponentInstances(false);
365         filter.setIgnoreGroups(false);
366         return validateComponentExists(componentId, componentType, filter);
367     }
368
369
370     private Either<PolicyDefinition, ResponseFormat> validateAndUpdatePolicy(Component component, PolicyDefinition policy) {
371         return getPolicyById(component, policy.getUniqueId())
372                 .left()
373                 .bind(np -> validateUpdatePolicyBeforeUpdate(policy, np, component.getPolicies()))
374                 .left()
375                 .bind(p -> updatePolicyOfComponent(component, p));
376     }
377
378     private Either<PolicyDefinition, ResponseFormat> validateAndUpdatePolicyProperties(Component component, String policyId, PropertyDataDefinition[] properties) {
379         return getPolicyById(component, policyId)
380                 .left()
381                 .bind(p -> validateUpdatePolicyPropertiesBeforeUpdate(p, properties))
382                 .left().bind(l -> updatePolicyOfComponent(component.getUniqueId(), l));
383     }
384
385     private Either<PolicyDefinition, ResponseFormat> updatePolicyOfComponent(String componentId, PolicyDefinition policy) {
386         return toscaOperationFacade.updatePolicyOfComponent(componentId, policy)
387                 .right()
388                 .bind(r -> Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(r))));
389     }
390
391     private Either<PolicyDefinition, ResponseFormat> validateUpdatePolicyPropertiesBeforeUpdate(PolicyDefinition policy, PropertyDataDefinition[] newProperties) {
392         if (CollectionUtils.isEmpty(policy.getProperties())) {
393             log.error("#validateUpdatePolicyPropertiesBeforeUpdate - failed to update properites of the policy. Properties were not found on the policy. ");
394             return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND));
395         }
396         return updatePropertyValues(policy, newProperties);
397     }
398
399     private Either<PolicyDefinition, ResponseFormat> updatePropertyValues(PolicyDefinition policy, PropertyDataDefinition[] newProperties) {
400
401         Map<String, PropertyDataDefinition> oldProperties = policy.getProperties().stream().collect(toMap(PropertyDataDefinition::getName, Function.identity()));
402         for (PropertyDataDefinition newProperty : newProperties) {
403             if (!oldProperties.containsKey(newProperty.getName())) {
404                 log.error("#updatePropertyValues - failed to update properites of the policy {}. Properties were not found on the policy. ", policy.getName());
405                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, newProperty.getName()));
406             }
407             Either<String, ResponseFormat> newPropertyValueEither = updateInputPropertyObjectValue(newProperty);
408             if (newPropertyValueEither.isRight()) {
409                 return Either.right(newPropertyValueEither.right().value());
410             }
411             oldProperties.get(newProperty.getName()).setValue(newPropertyValueEither.left().value());
412         }
413         return Either.left(policy);
414     }
415
416     private Either<PolicyDefinition, ResponseFormat> deletePolicy(Component component, String policyId) {
417         return getPolicyById(component, policyId)
418                 .left()
419                 .bind(p -> removePolicyFromComponent(component, p));
420     }
421
422     private Either<PolicyDefinition, ResponseFormat> updatePolicyOfComponent(Component component, PolicyDefinition policy) {
423         Either<PolicyDefinition, StorageOperationStatus> updatePolicyRes = toscaOperationFacade.updatePolicyOfComponent(component.getUniqueId(), policy);
424         if (updatePolicyRes.isRight()) {
425             log.error("#updatePolicyOfComponent - failed to update policy {} of the component {}. The status is {}. ", policy.getUniqueId(), component.getName(), updatePolicyRes.right().value());
426             return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updatePolicyRes.right().value())));
427         } else {
428             log.trace("#updatePolicyOfComponent - the policy with the name {} was updated. ", updatePolicyRes.left().value().getName());
429             return Either.left(updatePolicyRes.left().value());
430         }
431     }
432
433     private Either<PolicyDefinition, ResponseFormat> removePolicyFromComponent(Component component, PolicyDefinition policy) {
434         StorageOperationStatus updatePolicyStatus = toscaOperationFacade.removePolicyFromComponent(component.getUniqueId(), policy.getUniqueId());
435         if (updatePolicyStatus != StorageOperationStatus.OK) {
436             log.error("#removePolicyFromComponent - failed to remove policy {} from the component {}. The status is {}. ", policy.getUniqueId(), component.getName(), updatePolicyStatus);
437             return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updatePolicyStatus)));
438         } else {
439             log.trace("#removePolicyFromComponent - the policy with the name {} was deleted. ", updatePolicyStatus);
440             return Either.left(policy);
441         }
442     }
443
444     private Either<PolicyDefinition, ResponseFormat> validateUpdatePolicyBeforeUpdate(PolicyDefinition recievedPolicy, PolicyDefinition oldPolicy, Map<String, PolicyDefinition> policies) {
445         return validatePolicyFields(recievedPolicy, new PolicyDefinition(oldPolicy), policies)
446                 .right()
447                 .bind(r -> Either.right(componentsUtils.getResponseFormat(r, recievedPolicy.getName())));
448     }
449
450     private Either<PolicyDefinition, ResponseFormat> updateTargets(String componentId, PolicyDefinition policy, Map<PolicyTargetType, List<String>> targets, String policyId) {
451         if(policy == null){
452             return Either.right(componentsUtils.getResponseFormat(ActionStatus.POLICY_NOT_FOUND_ON_CONTAINER, policyId, componentId));
453         }
454         PolicyDefinition updatedPolicy = setPolicyTargets(policy, targets);
455         return updatePolicyOfComponent(componentId, updatedPolicy);
456     }
457
458 }