2 * ========================LICENSE_START=================================
5 * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved.
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.clients;
23 import static org.onap.ccsdk.oran.a1policymanagementservice.clients.OscA1Client.extractCreateSchema;
25 import com.google.gson.FieldNamingPolicy;
26 import com.google.gson.GsonBuilder;
28 import java.lang.invoke.MethodHandles;
29 import java.nio.charset.StandardCharsets;
30 import java.util.List;
31 import java.util.Optional;
36 import org.json.JSONObject;
37 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1MediatorAdapterI.A1MediatorRelIUriBuilder;
38 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig;
39 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
40 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.springframework.http.HttpStatus;
44 import org.springframework.web.reactive.function.client.WebClientResponseException;
46 import reactor.core.publisher.Flux;
47 import reactor.core.publisher.Mono;
50 * Client for accessing the A1 adapter in the CCSDK in ONAP using custom protocol defined in A1MediatorAdapterI.
52 @SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally
53 public class A1MediatorAdapterICCSDK implements A1Client {
55 static final int CONCURRENCY_RIC = 1; // How many parallel requests that is sent to one NearRT RIC
57 static com.google.gson.Gson gson = new GsonBuilder() //
58 .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES) //
62 public static class AdapterRequest {
63 private String nearRtRicUrl = null;
64 private String body = null;
66 public AdapterRequest(String url, String body) {
67 this.nearRtRicUrl = url;
71 public AdapterRequest() {}
75 public static class AdapterOutput {
76 private String body = null;
77 private int httpStatus = 0;
79 public AdapterOutput(int status, String body) {
80 this.httpStatus = status;
84 public AdapterOutput() {}
87 private static final String GET_POLICY_RPC = "getA1Policy";
88 private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
89 private final AsyncRestClient restClient;
90 private final RicConfig ricConfig;
91 private final A1MediatorRelIUriBuilder uriBuilder;
95 * Constructor that creates the REST client to use.
97 * @param ricConfig the configuration of the Near-RT RIC to communicate
99 * @param restClientFactory the factory for creating the REST Client
101 * @throws IllegalArgumentException when the protocolType is wrong.
103 public A1MediatorAdapterICCSDK(RicConfig ricConfig,
104 AsyncRestClientFactory restClientFactory) {
105 this(A1ProtocolType.CUSTOM_PROTOCOL, ricConfig, restClientFactory
106 .createRestClientNoHttpProxy(ricConfig.getControllerConfig().getBaseUrl() + "/rests/operations"));
110 * Constructor where the REST client to use is provided.
112 * @param protocolType the southbound protocol of the controller
113 * @param ricConfig the configuration of the Near-RT RIC to communicate
115 * @param restClient the REST client to use
117 * @throws IllegalArgumentException when the protocolType is illegal.
119 A1MediatorAdapterICCSDK(A1ProtocolType protocolType, RicConfig ricConfig, AsyncRestClient restClient) {
120 if (A1ProtocolType.CUSTOM_PROTOCOL.equals(protocolType)) {
121 this.restClient = restClient;
122 this.ricConfig = ricConfig;
123 this.uriBuilder = new A1MediatorAdapterI.A1MediatorRelIUriBuilder(ricConfig);
124 logger.debug("CcsdkA1AdapterClient for ric: {}, a1Controller: {}", ricConfig.getRicId(),
125 ricConfig.getControllerConfig());
127 logger.error("Not supported protocoltype: {}", protocolType);
128 throw new IllegalArgumentException("Not handled protocolversion: " + protocolType);
133 public Mono<List<String>> getPolicyTypeIdentities() {
134 return post(GET_POLICY_RPC, uriBuilder.createPolicyTypesUri(), Optional.empty()) //
135 .flatMapMany(A1AdapterJsonHelper::parseJsonArrayOfString) //
140 public Mono<List<String>> getPolicyIdentities() {
141 return getPolicyIds() //
146 public Mono<String> getPolicyTypeSchema(String policyTypeId) {
147 final String ricUrl = uriBuilder.createGetSchemaUri(policyTypeId);
148 return post(GET_POLICY_RPC, ricUrl, Optional.empty()) //
149 .flatMap(response -> extractCreateSchema(response, policyTypeId));
153 public Mono<String> putPolicy(Policy policy) {
154 String ricUrl = uriBuilder.createPutPolicyUri(policy.getType().getId(), policy.getId(),
155 policy.getStatusNotificationUri());
156 return post("putA1Policy", ricUrl, Optional.of(policy.getJson()));
160 public Mono<String> deletePolicy(Policy policy) {
161 return deletePolicyById(policy.getType().getId(), policy.getId());
165 public Flux<String> deleteAllPolicies(Set<String> excludePolicyIds) {
166 return getPolicyTypeIdentities() //
167 .flatMapMany(Flux::fromIterable) //
168 .flatMap(type -> deleteAllInstancesForType(uriBuilder, type, excludePolicyIds), CONCURRENCY_RIC);
171 private Flux<String> getInstancesForType(A1UriBuilder uriBuilder, String type) {
172 return post(GET_POLICY_RPC, uriBuilder.createGetPolicyIdsUri(type), Optional.empty()) //
173 .flatMapMany(A1AdapterJsonHelper::parseJsonArrayOfString);
176 private Flux<String> deleteAllInstancesForType(A1UriBuilder uriBuilder, String type, Set<String> excludePolicyIds) {
177 return getInstancesForType(uriBuilder, type) //
178 .filter(policyId -> !excludePolicyIds.contains(policyId)) //
179 .flatMap(policyId -> deletePolicyById(type, policyId), CONCURRENCY_RIC);
183 public Mono<A1ProtocolType> getProtocolVersion() {
184 return Mono.just(A1ProtocolType.CUSTOM_PROTOCOL);
188 public Mono<String> getPolicyStatus(Policy policy) {
189 String ricUrl = uriBuilder.createGetPolicyStatusUri(policy.getType().getId(), policy.getId());
190 return post("getA1PolicyStatus", ricUrl, Optional.empty());
193 private Flux<String> getPolicyIds() {
194 return getPolicyTypeIdentities() //
195 .flatMapMany(Flux::fromIterable)
196 .flatMap(type -> post(GET_POLICY_RPC, uriBuilder.createGetPolicyIdsUri(type), Optional.empty())) //
197 .flatMap(A1AdapterJsonHelper::parseJsonArrayOfString);
200 private Mono<String> deletePolicyById(String type, String policyId) {
201 String ricUrl = uriBuilder.createDeleteUri(type, policyId);
202 return post("deleteA1Policy", ricUrl, Optional.empty());
205 private Mono<String> post(String rpcName, String ricUrl, Optional<String> body) {
206 AdapterRequest inputParams = new AdapterRequest(ricUrl, body.isPresent() ? body.get() : null);
208 final String inputJsonString = A1AdapterJsonHelper.createInputJsonString(inputParams);
209 logger.debug("POST inputJsonString = {}", inputJsonString);
210 ControllerConfig controllerConfig = this.ricConfig.getControllerConfig();
212 .postWithAuthHeader(controllerUrl(rpcName), inputJsonString, controllerConfig.getUserName(),
213 controllerConfig.getPassword()) //
214 .flatMap(resp -> extractResponseBody(resp, ricUrl));
217 private Mono<String> extractResponse(JSONObject responseOutput, String ricUrl) {
218 AdapterOutput output = gson.fromJson(responseOutput.toString(), AdapterOutput.class);
220 String body = output.body == null ? "" : output.body;
221 if (HttpStatus.valueOf(output.httpStatus).is2xxSuccessful()) {
222 return Mono.just(body);
224 logger.debug("Error response: {} {}, from: {}", output.httpStatus, body, ricUrl);
225 byte[] responseBodyBytes = body.getBytes(StandardCharsets.UTF_8);
226 HttpStatus httpStatus = HttpStatus.valueOf(output.httpStatus);
227 WebClientResponseException responseException = new WebClientResponseException(httpStatus.value(),
228 httpStatus.getReasonPhrase(), null, responseBodyBytes, StandardCharsets.UTF_8, null);
230 return Mono.error(responseException);
234 private Mono<String> extractResponseBody(String responseStr, String ricUrl) {
235 return A1AdapterJsonHelper.getOutput(responseStr) //
236 .flatMap(responseOutput -> extractResponse(responseOutput, ricUrl));
239 private String controllerUrl(String rpcName) {
240 return "/A1-ADAPTER-API:" + rpcName;