2  * ========================LICENSE_START=================================
 
   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
 
  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.onap.ccsdk.oran.a1policymanagementservice.service.v3;
 
  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;
 
  46 import java.lang.invoke.MethodHandles;
 
  47 import java.util.ArrayList;
 
  48 import java.util.Collection;
 
  52 @RequiredArgsConstructor
 
  53 public class PolicyService {
 
  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;
 
  65     public Mono<ResponseEntity<PolicyObjectInformation>> createPolicyService
 
  66             (PolicyObjectInformation policyObjectInfo, ServerWebExchange serverWebExchange) {
 
  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             if (Boolean.FALSE.equals(helper.performPolicySchemaValidation(policy, policyType)))
 
  74                 return Mono.error(new ServiceException("Policy Type Schema validation failed in create", HttpStatus.BAD_REQUEST));
 
  75             return helper.isPolicyAlreadyCreated(policy,policies)
 
  76                     .doOnError(errorHandlingService::handleError)
 
  77                     .flatMap(policyBuilt -> authorizationService.authCheck(serverWebExchange, policy, AccessType.WRITE)
 
  78                     .doOnError(errorHandlingService::handleError)
 
  79                     .flatMap(policyNotUsed -> ric.getLock().lock(Lock.LockType.SHARED, "createPolicy"))
 
  80                     .flatMap(grant -> postPolicy(policy, grant))
 
  81                     .map(locationHeaderValue ->
 
  82                             new ResponseEntity<PolicyObjectInformation>(policyObjectInfo,helper.createHttpHeaders(
 
  83                                     "location",helper.buildURI(policy.getId(), serverWebExchange)), HttpStatus.CREATED))
 
  84                     .doOnError(errorHandlingService::handleError));
 
  85         } catch (Exception ex) {
 
  86             return Mono.error(ex);
 
  91     private Mono<String> postPolicy(Policy policy, Lock.Grant grant) {
 
  92         return  helper.checkRicStateIdle(policy.getRic())
 
  93                 .doOnError(errorHandlingService::handleError)
 
  94                 .flatMap(ric -> helper.checkSupportedType(ric, policy.getType()))
 
  95                 .doOnError(errorHandlingService::handleError)
 
  96                 .flatMap(a1ClientFactory::createA1Client)
 
  97                 .flatMap(a1Client -> a1Client.putPolicy(policy))
 
  98                 .doOnError(errorHandlingService::handleError)
 
  99                 .doOnNext(policyString -> policies.put(policy))
 
 100                 .doFinally(releaseLock -> grant.unlockBlocking())
 
 101                 .doOnError(errorHandlingService::handleError);
 
 104     public Mono<ResponseEntity<Object>> putPolicyService(String policyId, Object body, ServerWebExchange exchange) {
 
 106             Policy existingPolicy = policies.getPolicy(policyId);
 
 107             PolicyObjectInformation pos =
 
 108                     new PolicyObjectInformation(existingPolicy.getRic().getConfig().getRicId(), body, existingPolicy.getType().getId());
 
 109             Policy updatedPolicy = helper.buildPolicy(pos, existingPolicy.getType(), existingPolicy.getRic(), policyId, exchange);
 
 110             PolicyType policyType = policyTypes.getType(pos.getPolicyTypeId());
 
 111             if (Boolean.FALSE.equals(helper.performPolicySchemaValidation(updatedPolicy, policyType)))
 
 112                 return Mono.error(new ServiceException("Policy Type Schema validation failed in update", HttpStatus.BAD_REQUEST));
 
 113             Ric ric = existingPolicy.getRic();
 
 114             return authorizationService.authCheck(exchange, updatedPolicy, AccessType.WRITE)
 
 115                     .doOnError(errorHandlingService::handleError)
 
 116                     .flatMap(policy -> ric.getLock().lock(Lock.LockType.SHARED, "updatePolicy"))
 
 117                     .doOnError(errorHandlingService::handleError)
 
 118                     .flatMap(grant -> postPolicy(updatedPolicy, grant))
 
 119                     .map(header -> new ResponseEntity<Object>(policies.get(updatedPolicy.getId()).getJson(), HttpStatus.OK))
 
 120                     .doOnError(errorHandlingService::handleError);
 
 121         } catch(Exception ex) {
 
 122             return Mono.error(ex);
 
 126     public Mono<ResponseEntity<Flux<PolicyTypeInformation>>> getPolicyTypesService(String nearRtRicId, String typeName,
 
 127                                                                                    String compatibleWithVersion) throws ServiceException {
 
 128         if (compatibleWithVersion != null && typeName == null) {
 
 129             throw new ServiceException("Parameter " + Consts.COMPATIBLE_WITH_VERSION_PARAM + " can only be used when "
 
 130                     + Consts.TYPE_NAME_PARAM + " is given", HttpStatus.BAD_REQUEST);
 
 132         Collection<PolicyTypeInformation> listOfPolicyTypes = new ArrayList<>();
 
 133         if (nearRtRicId == null || nearRtRicId.isEmpty() || nearRtRicId.isBlank()) {
 
 134             for(Ric ric : rics.getRics()) {
 
 135                 Collection<PolicyType> filteredPolicyTypes = PolicyTypes.filterTypes(ric.getSupportedPolicyTypes(), typeName,
 
 136                         compatibleWithVersion);
 
 137                 listOfPolicyTypes.addAll(helper.toPolicyTypeInfoCollection(filteredPolicyTypes, ric));
 
 140             Ric ric = rics.get(nearRtRicId);
 
 142                 throw new EntityNotFoundException("Near-RT RIC not Found using ID: " +nearRtRicId);
 
 143             Collection<PolicyType> filteredPolicyTypes = PolicyTypes.filterTypes(ric.getSupportedPolicyTypes(), typeName,
 
 144                     compatibleWithVersion);
 
 145             listOfPolicyTypes.addAll(helper.toPolicyTypeInfoCollection(filteredPolicyTypes, ric));
 
 147         return Mono.just(new ResponseEntity<>(Flux.fromIterable(listOfPolicyTypes), HttpStatus.OK));
 
 150     public Mono<ResponseEntity<Flux<PolicyInformation>>> getPolicyIdsService(String policyTypeId, String nearRtRicId,
 
 151                                                                              String serviceId, String typeName,
 
 152                                                                              ServerWebExchange exchange) throws EntityNotFoundException {
 
 153         if ((policyTypeId != null && this.policyTypes.get(policyTypeId) == null))
 
 154             throw new EntityNotFoundException("Policy type not found using ID: " +policyTypeId);
 
 155         if ((nearRtRicId != null && this.rics.get(nearRtRicId) == null))
 
 156             throw new EntityNotFoundException("Near-RT RIC not found using ID: " +nearRtRicId);
 
 158         Collection<Policy> filtered = policies.filterPolicies(policyTypeId, nearRtRicId, serviceId, typeName);
 
 159         return Flux.fromIterable(filtered)
 
 160                 .flatMap(policy -> authorizationService.authCheck(exchange, policy, AccessType.READ))
 
 161                 .onErrorContinue((error,item) -> logger.warn("Error occurred during authorization check for " +
 
 162                         "policy {}: {}", item, error.getMessage()))
 
 164                 .map(authPolicies -> new ResponseEntity<>(helper.toFluxPolicyInformation(authPolicies), HttpStatus.OK))
 
 165                 .doOnError(error -> logger.error(error.getMessage()));
 
 168     public Mono<ResponseEntity<Object>> getPolicyService(String policyId, ServerWebExchange serverWebExchange)
 
 169             throws EntityNotFoundException{
 
 170             Policy policy = policies.getPolicy(policyId);
 
 171         return authorizationService.authCheck(serverWebExchange, policy, AccessType.READ)
 
 172                 .map(x -> new ResponseEntity<Object>(policy.getJson(), HttpStatus.OK))
 
 173                 .doOnError(errorHandlingService::handleError);
 
 176     public Mono<ResponseEntity<PolicyTypeObject>> getPolicyTypeDefinitionService(String policyTypeId)
 
 177             throws EntityNotFoundException{
 
 178         PolicyType singlePolicyType = policyTypes.get(policyTypeId);
 
 179         if (singlePolicyType == null)
 
 180             throw new EntityNotFoundException("PolicyType not found with ID: " + policyTypeId);
 
 182         PolicyTypeObject policyTypeObject = new PolicyTypeObject();
 
 184             policyTypeObject.setPolicySchema(gson.fromJson(singlePolicyType.getSchema(), Object.class));
 
 185         } catch (JsonSyntaxException e) {
 
 186             throw new RuntimeException("Failed to deserialize policy schema", e);
 
 189         return Mono.just(new ResponseEntity<PolicyTypeObject>(policyTypeObject, HttpStatus.OK));
 
 192     public Mono<ResponseEntity<Void>> deletePolicyService(String policyId, ServerWebExchange serverWebExchange)
 
 193             throws EntityNotFoundException {
 
 194         Policy singlePolicy = policies.getPolicy(policyId);
 
 195         return authorizationService.authCheck(serverWebExchange, singlePolicy, AccessType.WRITE)
 
 196                 .doOnError(errorHandlingService::handleError)
 
 197                 .flatMap(policy -> policy.getRic().getLock().lock(Lock.LockType.SHARED, "deletePolicy"))
 
 198                 .flatMap(grant -> deletePolicy(singlePolicy, grant))
 
 199                 .doOnError(errorHandlingService::handleError);
 
 202     private Mono<ResponseEntity<Void>> deletePolicy(Policy policy, Lock.Grant grant) {
 
 203         return  helper.checkRicStateIdle(policy.getRic())
 
 204                 .doOnError(errorHandlingService::handleError)
 
 205                 .flatMap(ric -> helper.checkSupportedType(ric, policy.getType()))
 
 206                 .doOnError(errorHandlingService::handleError)
 
 207                 .flatMap(a1ClientFactory::createA1Client)
 
 208                 .doOnError(errorHandlingService::handleError)
 
 209                 .flatMap(a1Client -> a1Client.deletePolicy(policy))
 
 210                 .doOnError(errorHandlingService::handleError)
 
 211                 .doOnNext(policyString -> policies.remove(policy))
 
 212                 .doFinally(releaseLock -> grant.unlockBlocking())
 
 213                 .map(successResponse -> new ResponseEntity<Void>(HttpStatus.NO_CONTENT))
 
 214                 .doOnError(errorHandlingService::handleError);
 
 217     private Mono<String> getStatus(Policy policy, Lock.Grant grant) {
 
 218         return  helper.checkRicStateIdle(policy.getRic())
 
 219                 .doOnError(errorHandlingService::handleError)
 
 220                 .flatMap(a1ClientFactory::createA1Client)
 
 221                 .flatMap(a1Client -> a1Client.getPolicyStatus(policy))
 
 222                 .doOnError(errorHandlingService::handleError)
 
 223                 .doFinally(releaseLock -> grant.unlockBlocking())
 
 224                 .doOnError(errorHandlingService::handleError);
 
 227     public Mono<ResponseEntity<Object>> getPolicyStatus(String policyId, ServerWebExchange exchange) throws Exception {
 
 228         Policy policy = policies.getPolicy(policyId);
 
 230         return authorizationService.authCheck(exchange, policy, AccessType.READ)
 
 231                 .doOnError(errorHandlingService::handleError)
 
 232                 .flatMap(policyLock -> policy.getRic().getLock().lock(Lock.LockType.SHARED, "getStatus"))
 
 233                 .doOnError(errorHandlingService::handleError)
 
 234                 .flatMap(grant -> getStatus(policy, grant))
 
 235                 .doOnError(errorHandlingService::handleError)
 
 236                 .map(successResponse -> new ResponseEntity<Object>(successResponse, HttpStatus.OK))
 
 237                 .doOnError(errorHandlingService::handleError);