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