f2ee6e18534def6ebd35db774cc4400025ea3cc6
[ccsdk/oran.git] /
1 /*-
2  * ========================LICENSE_START=================================
3  * ONAP : ccsdk oran
4  * ======================================================================
5  * Copyright (C) 2024-2025 OpenInfra Foundation Europe. 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.onap.ccsdk.oran.a1policymanagementservice.service.v3;
22
23 import com.google.gson.Gson;
24 import com.google.gson.JsonSyntaxException;
25 import lombok.RequiredArgsConstructor;
26 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
27 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.PolicyAuthorizationRequest.Input.AccessType;
28 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.Consts;
29 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.EntityNotFoundException;
30 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
31 import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyInformation;
32 import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyObjectInformation;
33 import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyTypeInformation;
34 import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyTypeObject;
35 import org.onap.ccsdk.oran.a1policymanagementservice.repository.*;
36 import org.onap.ccsdk.oran.a1policymanagementservice.util.v3.Helper;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.springframework.http.HttpStatus;
40 import org.springframework.http.ResponseEntity;
41 import org.springframework.stereotype.Service;
42 import org.springframework.web.server.ServerWebExchange;
43 import reactor.core.publisher.Flux;
44 import reactor.core.publisher.Mono;
45
46 import java.lang.invoke.MethodHandles;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Map;
50
51 @Service
52 @RequiredArgsConstructor
53 public class PolicyService {
54
55     private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
56     private final Helper helper;
57     private final Rics rics;
58     private final PolicyTypes policyTypes;
59     private final Policies policies;
60     private final AuthorizationService authorizationService;
61     private final A1ClientFactory a1ClientFactory;
62     private final ErrorHandlingService errorHandlingService;
63     private final Gson gson;
64
65     public Mono<ResponseEntity<PolicyObjectInformation>> createPolicyService
66             (PolicyObjectInformation policyObjectInfo, ServerWebExchange serverWebExchange) {
67         try {
68             if (Boolean.FALSE.equals(helper.jsonSchemaValidation(gson.toJson(policyObjectInfo.getPolicyObject(), Map.class))))
69                 return Mono.error(new ServiceException("Schema validation failed", HttpStatus.BAD_REQUEST));
70             Ric ric = rics.getRic(policyObjectInfo.getNearRtRicId());
71             PolicyType policyType = policyTypes.getType(policyObjectInfo.getPolicyTypeId());
72             Policy policy = helper.buildPolicy(policyObjectInfo, policyType, ric, helper.policyIdGeneration(policyObjectInfo), serverWebExchange);
73             return helper.isPolicyAlreadyCreated(policy,policies)
74                     .doOnError(errorHandlingService::handleError)
75                     .flatMap(policyBuilt -> authorizationService.authCheck(serverWebExchange, policy, AccessType.WRITE)
76                     .doOnError(errorHandlingService::handleError)
77                     .flatMap(policyNotUsed -> ric.getLock().lock(Lock.LockType.SHARED, "createPolicy"))
78                     .flatMap(grant -> postPolicy(policy, grant))
79                     .map(locationHeaderValue ->
80                             new ResponseEntity<PolicyObjectInformation>(policyObjectInfo,helper.createHttpHeaders(
81                                     "location",helper.buildURI(policy.getId(), serverWebExchange)), HttpStatus.CREATED))
82                     .doOnError(errorHandlingService::handleError));
83         } catch (Exception ex) {
84             return Mono.error(ex);
85         }
86
87     }
88
89     private Mono<String> postPolicy(Policy policy, Lock.Grant grant) {
90         return  helper.checkRicStateIdle(policy.getRic())
91                 .doOnError(errorHandlingService::handleError)
92                 .flatMap(ric -> helper.checkSupportedType(ric, policy.getType()))
93                 .doOnError(errorHandlingService::handleError)
94                 .flatMap(a1ClientFactory::createA1Client)
95                 .flatMap(a1Client -> a1Client.putPolicy(policy))
96                 .doOnError(errorHandlingService::handleError)
97                 .doOnNext(policyString -> policies.put(policy))
98                 .doFinally(releaseLock -> grant.unlockBlocking())
99                 .doOnError(errorHandlingService::handleError);
100     }
101
102     public Mono<ResponseEntity<Object>> putPolicyService(String policyId, Object body, ServerWebExchange exchange) {
103         try {
104             Policy existingPolicy = policies.getPolicy(policyId);
105             PolicyObjectInformation pos =
106                     new PolicyObjectInformation(existingPolicy.getRic().getConfig().getRicId(), body, existingPolicy.getType().getId());
107             Policy updatedPolicy = helper.buildPolicy(pos, existingPolicy.getType(), existingPolicy.getRic(), policyId, exchange);
108             Ric ric = existingPolicy.getRic();
109             return authorizationService.authCheck(exchange, updatedPolicy, AccessType.WRITE)
110                     .doOnError(errorHandlingService::handleError)
111                     .flatMap(policy -> ric.getLock().lock(Lock.LockType.SHARED, "updatePolicy"))
112                     .doOnError(errorHandlingService::handleError)
113                     .flatMap(grant -> postPolicy(updatedPolicy, grant))
114                     .map(header -> new ResponseEntity<Object>(policies.get(updatedPolicy.getId()).getJson(), HttpStatus.OK))
115                     .doOnError(errorHandlingService::handleError);
116         } catch(Exception ex) {
117             return Mono.error(ex);
118         }
119     }
120
121     public Mono<ResponseEntity<Flux<PolicyTypeInformation>>> getPolicyTypesService(String nearRtRicId, String typeName,
122                                                                                    String compatibleWithVersion) throws ServiceException {
123         if (compatibleWithVersion != null && typeName == null) {
124             throw new ServiceException("Parameter " + Consts.COMPATIBLE_WITH_VERSION_PARAM + " can only be used when "
125                     + Consts.TYPE_NAME_PARAM + " is given", HttpStatus.BAD_REQUEST);
126         }
127         Collection<PolicyTypeInformation> listOfPolicyTypes = new ArrayList<>();
128         if (nearRtRicId == null || nearRtRicId.isEmpty() || nearRtRicId.isBlank()) {
129             for(Ric ric : rics.getRics()) {
130                 Collection<PolicyType> filteredPolicyTypes = PolicyTypes.filterTypes(ric.getSupportedPolicyTypes(), typeName,
131                         compatibleWithVersion);
132                 listOfPolicyTypes.addAll(helper.toPolicyTypeInfoCollection(filteredPolicyTypes, ric));
133             }
134         } else {
135             Ric ric = rics.get(nearRtRicId);
136             if (ric == null)
137                 throw new EntityNotFoundException("Near-RT RIC not Found using ID: " +nearRtRicId);
138             Collection<PolicyType> filteredPolicyTypes = PolicyTypes.filterTypes(ric.getSupportedPolicyTypes(), typeName,
139                     compatibleWithVersion);
140             listOfPolicyTypes.addAll(helper.toPolicyTypeInfoCollection(filteredPolicyTypes, ric));
141         }
142         return Mono.just(new ResponseEntity<>(Flux.fromIterable(listOfPolicyTypes), HttpStatus.OK));
143     }
144
145     public Mono<ResponseEntity<Flux<PolicyInformation>>> getPolicyIdsService(String policyTypeId, String nearRtRicId,
146                                                                              String serviceId, String typeName,
147                                                                              ServerWebExchange exchange) throws EntityNotFoundException {
148         if ((policyTypeId != null && this.policyTypes.get(policyTypeId) == null))
149             throw new EntityNotFoundException("Policy type not found using ID: " +policyTypeId);
150         if ((nearRtRicId != null && this.rics.get(nearRtRicId) == null))
151             throw new EntityNotFoundException("Near-RT RIC not found using ID: " +nearRtRicId);
152
153         Collection<Policy> filtered = policies.filterPolicies(policyTypeId, nearRtRicId, serviceId, typeName);
154         return Flux.fromIterable(filtered)
155                 .flatMap(policy -> authorizationService.authCheck(exchange, policy, AccessType.READ))
156                 .onErrorContinue((error,item) -> logger.warn("Error occurred during authorization check for " +
157                         "policy {}: {}", item, error.getMessage()))
158                 .collectList()
159                 .map(authPolicies -> new ResponseEntity<>(helper.toFluxPolicyInformation(authPolicies), HttpStatus.OK))
160                 .doOnError(error -> logger.error(error.getMessage()));
161     }
162
163     public Mono<ResponseEntity<Object>> getPolicyService(String policyId, ServerWebExchange serverWebExchange)
164             throws EntityNotFoundException{
165             Policy policy = policies.getPolicy(policyId);
166         return authorizationService.authCheck(serverWebExchange, policy, AccessType.READ)
167                 .map(x -> new ResponseEntity<Object>(policy.getJson(), HttpStatus.OK))
168                 .doOnError(errorHandlingService::handleError);
169     }
170
171     public Mono<ResponseEntity<PolicyTypeObject>> getPolicyTypeDefinitionService(String policyTypeId)
172             throws EntityNotFoundException{
173         PolicyType singlePolicyType = policyTypes.get(policyTypeId);
174         if (singlePolicyType == null)
175             throw new EntityNotFoundException("PolicyType not found with ID: " + policyTypeId);
176
177         PolicyTypeObject policyTypeObject = new PolicyTypeObject();
178         try {
179             policyTypeObject.setPolicySchema(gson.fromJson(singlePolicyType.getSchema(), Object.class));
180         } catch (JsonSyntaxException e) {
181             throw new RuntimeException("Failed to deserialize policy schema", e);
182         }
183
184         return Mono.just(new ResponseEntity<PolicyTypeObject>(policyTypeObject, HttpStatus.OK));
185     }
186
187     public Mono<ResponseEntity<Void>> deletePolicyService(String policyId, ServerWebExchange serverWebExchange)
188             throws EntityNotFoundException {
189         Policy singlePolicy = policies.getPolicy(policyId);
190         return authorizationService.authCheck(serverWebExchange, singlePolicy, AccessType.WRITE)
191                 .doOnError(errorHandlingService::handleError)
192                 .flatMap(policy -> policy.getRic().getLock().lock(Lock.LockType.SHARED, "deletePolicy"))
193                 .flatMap(grant -> deletePolicy(singlePolicy, grant))
194                 .doOnError(errorHandlingService::handleError);
195     }
196
197     private Mono<ResponseEntity<Void>> deletePolicy(Policy policy, Lock.Grant grant) {
198         return  helper.checkRicStateIdle(policy.getRic())
199                 .doOnError(errorHandlingService::handleError)
200                 .flatMap(ric -> helper.checkSupportedType(ric, policy.getType()))
201                 .doOnError(errorHandlingService::handleError)
202                 .flatMap(a1ClientFactory::createA1Client)
203                 .doOnError(errorHandlingService::handleError)
204                 .flatMap(a1Client -> a1Client.deletePolicy(policy))
205                 .doOnError(errorHandlingService::handleError)
206                 .doOnNext(policyString -> policies.remove(policy))
207                 .doFinally(releaseLock -> grant.unlockBlocking())
208                 .map(successResponse -> new ResponseEntity<Void>(HttpStatus.NO_CONTENT))
209                 .doOnError(errorHandlingService::handleError);
210     }
211
212     private Mono<String> getStatus(Policy policy, Lock.Grant grant) {
213         return  helper.checkRicStateIdle(policy.getRic())
214                 .doOnError(errorHandlingService::handleError)
215                 .flatMap(a1ClientFactory::createA1Client)
216                 .flatMap(a1Client -> a1Client.getPolicyStatus(policy))
217                 .doOnError(errorHandlingService::handleError)
218                 .doFinally(releaseLock -> grant.unlockBlocking())
219                 .doOnError(errorHandlingService::handleError);
220     }
221
222     public Mono<ResponseEntity<Object>> getPolicyStatus(String policyId, ServerWebExchange exchange) throws Exception {
223         Policy policy = policies.getPolicy(policyId);
224
225         return authorizationService.authCheck(exchange, policy, AccessType.READ)
226                 .doOnError(errorHandlingService::handleError)
227                 .flatMap(policyLock -> policy.getRic().getLock().lock(Lock.LockType.SHARED, "getStatus"))
228                 .doOnError(errorHandlingService::handleError)
229                 .flatMap(grant -> getStatus(policy, grant))
230                 .doOnError(errorHandlingService::handleError)
231                 .map(successResponse -> new ResponseEntity<Object>(successResponse, HttpStatus.OK))
232                 .doOnError(errorHandlingService::handleError);
233     }
234 }