NONRTRIC PMS, Cherry-pick the recent changes into Jakarta Release 23/130323/1 1.3.3
authorPatrikBuhr <patrik.buhr@est.tech>
Wed, 11 May 2022 11:10:40 +0000 (13:10 +0200)
committerPatrikBuhr <patrik.buhr@est.tech>
Wed, 17 Aug 2022 10:53:13 +0000 (12:53 +0200)
Sqasch of cherrypicked commits for the maintenance release.

Issue-ID: CCSDK-3742
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
NONRTRIC PMS added support for custom A1 adapters

Added support for added external A1-P adapter. This makes it possible to design and include
adapter to APIs for accessing of A1 policies (in a NearRT-RIC) without any changes in this
SW.

Issue-ID: CCSDK-3655
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
NONRTRIC PMS added support for custom A1 adapters

Updates of the json schema for configuration. Made it stricter and added the customAdapterClass prpoperty.

Issue-ID: CCSDK-3655
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
NONRTRIC PMS removalof usage of immutable

Issue-ID: CCSDK-3629
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
NONRTRIC PMS, Sporadic instability

Attempt to stablize the synch.

Issue-ID: CCSDK-3683
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
NONRTRIC PMS, Sporadic instability

Attempt to stablize the synch.

Issue-ID: CCSDK-3683
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
NONRTRIC PMS, Sporadic instability

Some further simplifications and added test.

Issue-ID: CCSDK-3683
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
Change-Id: I1ec98017d63047a0036db5ea12f770db00b1152b

NONRTRIC PMS, updated SDNC rest interface

Update path and output-json for SDNC rest interface - A1 Kohn

Issue-ID: CCSDK-3193
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
NONRTRIC PMS, Bugfix

If the auth-token-file parameter in the file application.yaml is missing, it would not default to an empty file name.

Issue-ID: CCSDK-3683
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
NONRTRIC PMS, updated certs

Updated certificate (which was expired).

Issue-ID: CCSDK-3683
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
Change-Id: I34ffc932d855ba3b94cfff23dcb56f30780dbecc

67 files changed:
a1-policy-management/README.md
a1-policy-management/api/pms-api.json
a1-policy-management/api/pms-api.yaml
a1-policy-management/config/README
a1-policy-management/config/application.yaml
a1-policy-management/config/application_configuration.json
a1-policy-management/config/keystore.jks
a1-policy-management/config/truststore.jks
a1-policy-management/pom.xml
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/SwaggerConfig.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1AdapterJsonHelper.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1Client.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClient.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1Client.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SecurityContext.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion1.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion2.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParser.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ControllerConfig.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/RicConfig.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/WebClientConfig.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbackInfo.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/VoidResponse.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyIdList.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfoList.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyStatusInfo.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeIdList.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeInfo.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfo.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfoList.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceRegistrationInfo.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceStatus.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceStatusList.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/StatusController.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Ric.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervision.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTask.java
a1-policy-management/src/main/resources/application_configuration_schema.json
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/MockPolicyManagementService.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactoryTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientHelper.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClientTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1ClientTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientV2Test.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConfigurationControllerTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTaskTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervisionTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/ServiceSupervisionTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1Client.java
a1-policy-management/src/test/resources/keystore.jks [deleted file]
a1-policy-management/src/test/resources/test_application_configuration.json
a1-policy-management/src/test/resources/test_application_configuration_with_dmaap_config.json
a1-policy-management/src/test/resources/truststore.jks [deleted file]
docs/offeredapis/swagger/pms-api.json
docs/offeredapis/swagger/pms-api.yaml

index 5c619c2..c25b29d 100644 (file)
@@ -75,7 +75,7 @@ Sample Response Message to DMaaP:
 ## License
 
 ONAP : ccsdk oran
-Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+Copyright (C) 2019-2022 Nordix Foundation. All rights reserved.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
index 9fc8e7b..5c5915c 100644 (file)
@@ -79,7 +79,7 @@
                 },
                 "keep_alive_interval_seconds": {
                     "format": "int64",
-                    "description": "keep alive interval for the service. This is a heartbeat supervision of the service, which in regular intervals must invoke a 'keepalive' REST call. When a service does not invoke this call within the given time, it is considered unavailable. An unavailable service will be automatically deregistered and its policies will be deleted. Value 0 means no timeout supervision.",
+                    "description": "keep alive interval for the service. This is used to enable optional heartbeat supervision of the service. If set (> 0) the registered service should regularly invoke a 'keepalive' REST call. When a service fails to invoke this 'keepalive' call within the configured time, the service is considered unavailable. An unavailable service will be automatically deregistered and its policies will be deleted. Value 0 means timeout supervision is disabled.",
                     "type": "integer"
                 }
             }
         },
         "/a1-policy/v2/services/{service_id}/keepalive": {"put": {
             "summary": "Heartbeat indicates that the service is running",
-            "description": "A registered service must call this in regular intervals to indicate that it is in operation. Absence of this call will lead to that the service will be deregistered and all its policies are removed.",
+            "description": "A registered service should invoke this operation regularly to indicate that it is still alive. If a registered service fails to invoke this operation before the end of a timeout period the service will be deregistered and all its A1 policies wil be removed. (This timeout can be set or disabled when each service is initially registered)",
             "operationId": "keepAliveService",
             "responses": {
                 "200": {
             "url": "http://www.apache.org/licenses/LICENSE-2.0"
         },
         "description": "<h2>General<\/h2><p>The O-RAN Non-RT RIC Policy Management Service provides a REST API for management of A1 policies. <br/>The main tasks of the service are:<\/p><ul><li>A1 Policy creation, modification and deletion.<\/li><li>Monitoring and maintaining consistency of the SMO view of A1 policies and the Near-RT RICs<\/li><li>Maintaining a view of supported Near-RT RIC policy types<\/li><li>Supervision of using services (R-APPs). When a service is unavailable, its policies are removed.<\/li><\/ul><h2>APIs provided by the service<\/h2><h3>A1 Policy Management<\/h3><p>This is an API for management of A1 Policies.<\/p><ul><li>A1 Policy retrieval, creation, modification and deletion.<\/li><li>Retrieval of supported A1 Policy types for a Near-RT RIC<\/li><li>Retrieval of status for existing A1 policies<\/li><\/ul><h3>Management of configuration<\/h3><p>API for updating and retrieval of the component configuration. Note that there other ways to maintain the configuration.<\/p><h3>Callbacks<\/h3><p>These are endpoints that are invoked by this service. The callbacks are registered in this service at service registration.<\/p><h3>NearRT-RIC Repository<\/h3><p>This is an API that provides support for looking up a NearRT-RIC. Each A1 policy is targeted for one Near-RT RIC.<\/p><h3>Health Check<\/h3><p>API used for supervision of the PMS component.<\/p><h3>Service Registry and Supervision<\/h3><p>API used for registering services that uses PMS. Each A1 policy is owned by a service. PMS can supervise each registered service and will automatically remove policies for unavailable services.<\/p>",
-        "title": "A1 Policy management service",
+        "title": "A1 Policy Management Service",
         "version": "1.1.0"
     },
     "tags": [
index 3fd496b..1f84399 100644 (file)
@@ -1,6 +1,6 @@
 openapi: 3.0.1
 info:
-  title: A1 Policy management service
+  title: A1 Policy Management Service
   description: <h2>General</h2><p>The O-RAN Non-RT RIC Policy Management Service provides
     a REST API for management of A1 policies. <br/>The main tasks of the service are:</p><ul><li>A1
     Policy creation, modification and deletion.</li><li>Monitoring and maintaining
@@ -434,9 +434,11 @@ paths:
       tags:
       - Service Registry and Supervision
       summary: Heartbeat indicates that the service is running
-      description: A registered service must call this in regular intervals to indicate
-        that it is in operation. Absence of this call will lead to that the service
-        will be deregistered and all its policies are removed.
+      description: A registered service should invoke this operation regularly to
+        indicate that it is still alive. If a registered service fails to invoke this
+        operation before the end of a timeout period the service will be deregistered
+        and all its A1 policies wil be removed. (This timeout can be set or disabled
+        when each service is initially registered)
       operationId: keepAliveService
       parameters:
       - name: service_id
@@ -896,12 +898,13 @@ components:
           description: identity of the service
         keep_alive_interval_seconds:
           type: integer
-          description: keep alive interval for the service. This is a heartbeat supervision
-            of the service, which in regular intervals must invoke a 'keepalive' REST
-            call. When a service does not invoke this call within the given time,
-            it is considered unavailable. An unavailable service will be automatically
-            deregistered and its policies will be deleted. Value 0 means no timeout
-            supervision.
+          description: keep alive interval for the service. This is used to enable
+            optional heartbeat supervision of the service. If set (> 0) the registered
+            service should regularly invoke a 'keepalive' REST call. When a service
+            fails to invoke this 'keepalive' call within the configured time, the
+            service is considered unavailable. An unavailable service will be automatically
+            deregistered and its policies will be deleted. Value 0 means timeout supervision
+            is disabled.
           format: int64
       description: Information for one service
     policy_info_list_v2:
index b54a675..42e0b7b 100644 (file)
@@ -3,13 +3,15 @@ The keystore.jks and truststore.jks files are created by using the following com
 1) Create a CA certificate and a private key:
 
 openssl genrsa -des3 -out CA-key.pem 2048
-openssl req -new -key CA-key.pem -x509 -days 1000 -out CA-cert.pem 
+openssl req -new -key CA-key.pem -x509 -days 3600 -out CA-cert.pem
 
 2) Create a keystore with a private key entry that is signed by the CA:
 
+Note: the "your name" must be "localhost" for the unittest to work.
+
 keytool -genkeypair -alias policy_agent -keyalg RSA -keysize 2048 -keystore keystore.jks -validity 3650 -storepass policy_agent
 keytool -certreq -alias policy_agent -file request.csr -keystore keystore.jks -ext san=dns:your.domain.com -storepass policy_agent
-openssl x509 -req -days 365 -in request.csr -CA CA-cert.pem -CAkey CA-key.pem -CAcreateserial -out ca_signed-cert.pem
+openssl x509 -req -days 3650 -in request.csr -CA CA-cert.pem -CAkey CA-key.pem -CAcreateserial -out ca_signed-cert.pem
 keytool -importcert -alias ca_cert -file CA-cert.pem -keystore keystore.jks -trustcacerts -storepass policy_agent
 keytool -importcert -alias policy_agent -file ca_signed-cert.pem -keystore keystore.jks -trustcacerts -storepass policy_agent
 
index 7628624..f0f5337 100644 (file)
@@ -56,6 +56,8 @@ server:
       key-store: /opt/app/policy-agent/etc/cert/keystore.jks
       key-password: policy_agent
       key-alias: policy_agent
+      # trust-store-password:
+      # trust-store:
 app:
   # Location of the component configuration file.
   filepath: /opt/app/policy-agent/data/application_configuration.json
@@ -80,4 +82,3 @@ app:
   # A file containing an authorization token, which shall be inserted in each HTTP header (authorization).
   # If the file name is empty, no authorization token is sent.
   auth-token-file:
-
index 6187c86..29d5923 100644 (file)
@@ -1,6 +1,6 @@
 {
    "description": "Application configuration",
-   "config": {  
+   "config": {
       "controller": [
          {
             "name": "controller1",
          {
             "name": "ric1",
             "baseUrl": "http://ric1:8085/",
-            "controller": "controller1",
             "managedElementIds": [
                "kista_1",
                "kista_2"
             ]
+         },
+         {
+            "name": "ric2",
+            "baseUrl": "http://localhost:8081/",
+            "customAdapterClass": "org.onap.ccsdk.oran.a1policymanagementservice.clients.StdA1ClientVersion2$Factory",
+            "managedElementIds": [
+               "kista_3",
+               "kista_4"
+            ]
+         },
+         {
+            "name": "ric3",
+            "baseUrl": "http://ric1:8085/",
+            "controller": "controller1",
+            "managedElementIds": [
+               "kista_5",
+               "kista_6"
+            ]
          }
       ]
    }
-}
+}
\ No newline at end of file
index 48c3b33..563c67b 100644 (file)
Binary files a/a1-policy-management/config/keystore.jks and b/a1-policy-management/config/keystore.jks differ
index 760261e..50a0f9e 100644 (file)
Binary files a/a1-policy-management/config/truststore.jks and b/a1-policy-management/config/truststore.jks differ
index da44d2a..be98178 100644 (file)
@@ -35,7 +35,7 @@
         <java.version.source>11</java.version.source>
         <java.version.target>11</java.version.target>
         <springfox.version>3.0.0</springfox.version>
-        <immutable.version>2.9.0</immutable.version>
+        <gson.version>2.9.0</gson.version>
         <json.version>20220320</json.version>
         <formatter-maven-plugin.version>2.13.0</formatter-maven-plugin.version>
         <spotless-maven-plugin.version>2.5.0</spotless-maven-plugin.version>
         <ccsdk.project.version>${project.version}</ccsdk.project.version>
     </properties>
     <dependencies>
-        <dependency>
-            <groupId>org.springdoc</groupId>
-            <artifactId>springdoc-openapi-ui</artifactId>
-            <version>1.6.6</version>
-        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot</artifactId>
             <artifactId>guava</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.immutables</groupId>
-            <artifactId>value</artifactId>
-            <version>${immutable.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.immutables</groupId>
+            <groupId>com.google.code.gson</groupId>
             <artifactId>gson</artifactId>
-            <version>${immutable.version}</version>
+            <version>${gson.version}</version>
         </dependency>
         <dependency>
             <groupId>org.json</groupId>
             <scope>runtime</scope>
         </dependency>
         <!-- TEST -->
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-ui</artifactId>
+            <version>1.6.6</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-test</artifactId>
             </plugin>
         </plugins>
     </build>
-</project>
+</project>
\ No newline at end of file
index 774b236..4e4ec2d 100644 (file)
@@ -60,7 +60,8 @@ public class SwaggerConfig {
             "<li>A1 Policy creation, modification and deletion.</li>" + //
             "<li>Monitoring and maintaining consistency of the SMO view of A1 policies and the Near-RT RICs</li>" + //
             "<li>Maintaining a view of supported Near-RT RIC policy types</li>" + //
-            "<li>Supervision of using services (R-APPs). When a service is unavailable, its policies are removed.</li>" + //
+            "<li>Supervision of using services (R-APPs). When a service is unavailable, its policies are removed.</li>"
+            + //
             "</ul>" + //
             "<h2>APIs provided by the service</h2>" + //
             H3 + PolicyController.API_NAME + H3_END + //
index d4c264d..60dca3b 100644 (file)
@@ -31,7 +31,6 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.json.JSONArray;
-import org.json.JSONException;
 import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -47,7 +46,7 @@ class A1AdapterJsonHelper {
     private static Gson gson = new GsonBuilder() //
             .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES) //
             .create();
-    private static final String OUTPUT = "output";
+    private static final String OUTPUT = "A1-ADAPTER-API:output";
     private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     private A1AdapterJsonHelper() {}
@@ -63,7 +62,7 @@ class A1AdapterJsonHelper {
                 }
             }
             return Flux.fromIterable(arrayList);
-        } catch (JSONException ex) { // invalid json
+        } catch (Exception ex) { // invalid json
             logger.debug("Invalid json {}", ex.getMessage());
             return Flux.error(ex);
         }
@@ -88,7 +87,7 @@ class A1AdapterJsonHelper {
             JSONObject outputJson = new JSONObject(response);
             JSONObject responseParams = outputJson.getJSONObject(OUTPUT);
             return Mono.just(responseParams);
-        } catch (JSONException ex) { // invalid json
+        } catch (Exception ex) { // invalid json
             logger.debug("Invalid json {}", ex.getMessage());
             return Mono.error(ex);
         }
@@ -110,7 +109,7 @@ class A1AdapterJsonHelper {
             JSONObject schemaObject = jsonObject.getJSONObject("policySchema");
             String schemaString = schemaObject.toString();
             return Mono.just(schemaString);
-        } catch (JSONException ex) { // invalid json
+        } catch (Exception ex) { // invalid json
             logger.debug("Invalid json {}", ex.getMessage());
             return Mono.error(ex);
         }
index 5e498e4..a691ee1 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.clients;
 
 import java.util.List;
 
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
 
 import reactor.core.publisher.Flux;
@@ -33,6 +34,10 @@ import reactor.core.publisher.Mono;
  */
 public interface A1Client {
 
+    public interface Factory {
+        A1Client create(RicConfig ricConfig, AsyncRestClientFactory restClientFactory);
+    }
+
     public enum A1ProtocolType {
         UNKNOWN, //
         STD_V1_1, // STD A1 version 1.1
@@ -40,7 +45,8 @@ public interface A1Client {
         OSC_V1, // OSC 'A1'
         CCSDK_A1_ADAPTER_STD_V1_1, // CCSDK_A1_ADAPTER with STD A1 version 1.1 southbound
         CCSDK_A1_ADAPTER_STD_V2_0_0, // CCSDK_A1_ADAPTER with STD A1 version 2.0.0 southbound
-        CCSDK_A1_ADAPTER_OSC_V1 // CCSDK_A1_ADAPTER with OSC 'A1' southbound
+        CCSDK_A1_ADAPTER_OSC_V1, // CCSDK_A1_ADAPTER with OSC 'A1' southbound
+        CUSTOM_PROTOCOL // Some other protocol handled by some custom A1 adapter class.
     }
 
     public Mono<A1ProtocolType> getProtocolVersion();
index 1d465c3..75ba251 100644 (file)
 
 package org.onap.ccsdk.oran.a1policymanagementservice.clients;
 
+import java.lang.reflect.Constructor;
+
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
 import org.slf4j.Logger;
@@ -83,6 +86,8 @@ public class A1ClientFactory {
                 || version == A1ProtocolType.CCSDK_A1_ADAPTER_OSC_V1
                 || version == A1ProtocolType.CCSDK_A1_ADAPTER_STD_V2_0_0) {
             return new CcsdkA1AdapterClient(version, ric.getConfig(), getControllerConfig(ric), this.restClientFactory);
+        } else if (version == A1ProtocolType.CUSTOM_PROTOCOL) {
+            return createCustomAdapter(ric);
         } else {
             logger.error("Unhandled protocol: {}", version);
             throw new ServiceException("Unhandled protocol");
@@ -90,7 +95,7 @@ public class A1ClientFactory {
     }
 
     private ControllerConfig getControllerConfig(Ric ric) throws ServiceException {
-        String controllerName = ric.getConfig().controllerName();
+        String controllerName = ric.getConfig().getControllerName();
         if (controllerName.isEmpty()) {
             ric.setProtocolVersion(A1ProtocolType.UNKNOWN);
             throw new ServiceException("No controller configured for Near-RT RIC: " + ric.id());
@@ -103,8 +108,27 @@ public class A1ClientFactory {
         }
     }
 
+    private A1Client createCustomAdapter(Ric ric) throws ServiceException {
+        try {
+            Class<?> clazz = Class.forName(ric.getConfig().getCustomAdapterClass());
+            if (A1Client.class.isAssignableFrom(clazz)) {
+                Constructor<?> constructor = clazz.getConstructor(RicConfig.class, AsyncRestClientFactory.class);
+                return (A1Client) constructor.newInstance(ric.getConfig(), this.restClientFactory);
+            } else if (A1Client.Factory.class.isAssignableFrom(clazz)) {
+                A1Client.Factory factory = (A1Client.Factory) clazz.getDeclaredConstructor().newInstance();
+                return factory.create(ric.getConfig(), this.restClientFactory);
+            } else {
+                throw new ServiceException("The custom class must either implement A1Client.Factory or A1Client");
+            }
+        } catch (ClassNotFoundException e) {
+            throw new ServiceException("Could not find class: " + ric.getConfig().getCustomAdapterClass(), e);
+        } catch (Exception e) {
+            throw new ServiceException("Cannot create custom adapter: " + ric.getConfig().getCustomAdapterClass(), e);
+        }
+    }
+
     private void assertNoControllerConfig(Ric ric, A1ProtocolType version) throws ServiceException {
-        if (!ric.getConfig().controllerName().isEmpty()) {
+        if (!ric.getConfig().getControllerName().isEmpty()) {
             ric.setProtocolVersion(A1ProtocolType.UNKNOWN);
             throw new ServiceException(
                     "Controller config should be empty, ric: " + ric.id() + " when using protocol version: " + version);
@@ -128,9 +152,7 @@ public class A1ClientFactory {
                     .doOnNext(ric::setProtocolVersion)
                     .doOnNext(version -> logger.debug("Established protocol version:{} for Near-RT RIC: {}", version,
                             ric.id())) //
-                    .doOnError(notUsed -> logger.warn("Could not get protocol version from Near-RT RIC: {}", ric.id())) //
-                    .onErrorResume(
-                            notUsed -> Mono.error(new ServiceException("Protocol negotiation failed for " + ric.id())));
+                    .doOnError(notUsed -> logger.warn("Could not get protocol version from Near-RT RIC: {}", ric.id()));
         } else {
             return Mono.just(ric.getProtocolVersion());
         }
index 959d85e..c4afdb2 100644 (file)
@@ -154,8 +154,8 @@ public class AsyncRestClient {
     }
 
     private boolean isHttpProxyConfigured() {
-        return httpProxyConfig != null && httpProxyConfig.httpProxyPort() > 0
-                && !httpProxyConfig.httpProxyHost().isEmpty();
+        return httpProxyConfig != null && httpProxyConfig.getHttpProxyPort() > 0
+                && !httpProxyConfig.getHttpProxyHost().isEmpty();
     }
 
     private HttpClient buildHttpClient() {
@@ -172,7 +172,7 @@ public class AsyncRestClient {
 
         if (isHttpProxyConfigured()) {
             httpClient = httpClient.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP)
-                    .host(httpProxyConfig.httpProxyHost()).port(httpProxyConfig.httpProxyPort()));
+                    .host(httpProxyConfig.getHttpProxyHost()).port(httpProxyConfig.getHttpProxyPort()));
         }
         return httpClient;
     }
index 844db54..204af9c 100644 (file)
@@ -60,7 +60,7 @@ public class AsyncRestClientFactory {
     public AsyncRestClientFactory(WebClientConfig clientConfig, SecurityContext securityContext) {
         if (clientConfig != null) {
             this.sslContextFactory = new CachingSslContextFactory(clientConfig);
-            this.httpProxyConfig = clientConfig.httpProxyConfig();
+            this.httpProxyConfig = clientConfig.getHttpProxyConfig();
         } else {
             logger.warn("No configuration for web client defined, HTTPS will not work");
             this.sslContextFactory = null;
@@ -105,8 +105,8 @@ public class AsyncRestClientFactory {
         private SslContext createSslContext(KeyManagerFactory keyManager)
                 throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
             if (this.clientConfig.isTrustStoreUsed()) {
-                return createSslContextRejectingUntrustedPeers(this.clientConfig.trustStore(),
-                        this.clientConfig.trustStorePassword(), keyManager);
+                return createSslContextRejectingUntrustedPeers(this.clientConfig.getTrustStore(),
+                        this.clientConfig.getTrustStorePassword(), keyManager);
             } else {
                 // Trust anyone
                 return SslContextBuilder.forClient() //
@@ -154,10 +154,10 @@ public class AsyncRestClientFactory {
         private KeyManagerFactory createKeyManager() throws NoSuchAlgorithmException, CertificateException, IOException,
                 UnrecoverableKeyException, KeyStoreException {
             final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-            final KeyStore keyStore = KeyStore.getInstance(this.clientConfig.keyStoreType());
-            final String keyStoreFile = this.clientConfig.keyStore();
-            final String keyStorePassword = this.clientConfig.keyStorePassword();
-            final String keyPassword = this.clientConfig.keyPassword();
+            final KeyStore keyStore = KeyStore.getInstance(this.clientConfig.getKeyStoreType());
+            final String keyStoreFile = this.clientConfig.getKeyStore();
+            final String keyStorePassword = this.clientConfig.getKeyStorePassword();
+            final String keyPassword = this.clientConfig.getKeyPassword();
             try (final InputStream inputStream = new FileInputStream(keyStoreFile)) {
                 keyStore.load(inputStream, keyStorePassword.toCharArray());
             }
index c3f0040..df6faad 100644 (file)
@@ -29,10 +29,12 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
 
-import org.immutables.value.Value;
+import lombok.Getter;
+
 import org.json.JSONObject;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,20 +52,30 @@ public class CcsdkA1AdapterClient implements A1Client {
 
     static final int CONCURRENCY_RIC = 1; // How many paralell requests that is sent to one NearRT RIC
 
-    @Value.Immutable
-    @org.immutables.gson.Gson.TypeAdapters
-    public interface AdapterRequest {
-        public String nearRtRicUrl();
+    @Getter
+    public static class AdapterRequest {
+        private String nearRtRicUrl = null;
+        private String body = null;
+
+        public AdapterRequest(String url, String body) {
+            this.nearRtRicUrl = url;
+            this.body = body;
+        }
 
-        public Optional<String> body();
+        public AdapterRequest() {}
     }
 
-    @Value.Immutable
-    @org.immutables.gson.Gson.TypeAdapters
-    public interface AdapterOutput {
-        public Optional<String> body();
+    @Getter
+    public static class AdapterOutput {
+        private String body = null;
+        private int httpStatus = 0;
+
+        public AdapterOutput(int status, String body) {
+            this.httpStatus = status;
+            this.body = body;
+        }
 
-        public int httpStatus();
+        public AdapterOutput() {}
     }
 
     static com.google.gson.Gson gson = new GsonBuilder() //
@@ -93,7 +105,7 @@ public class CcsdkA1AdapterClient implements A1Client {
     public CcsdkA1AdapterClient(A1ProtocolType protocolType, RicConfig ricConfig, ControllerConfig controllerConfig,
             AsyncRestClientFactory restClientFactory) {
         this(protocolType, ricConfig, controllerConfig,
-                restClientFactory.createRestClientNoHttpProxy(controllerConfig.baseUrl() + "/restconf/operations"));
+                restClientFactory.createRestClientNoHttpProxy(controllerConfig.getBaseUrl() + "/rests/operations"));
     }
 
     /**
@@ -119,11 +131,11 @@ public class CcsdkA1AdapterClient implements A1Client {
             this.ricConfig = ricConfig;
             this.protocolType = protocolType;
             this.controllerConfig = controllerConfig;
-            logger.debug("CcsdkA1AdapterClient for ric: {}, a1Controller: {}", ricConfig.ricId(), controllerConfig);
+            logger.debug("CcsdkA1AdapterClient for ric: {}, a1Controller: {}", ricConfig.getRicId(), controllerConfig);
         } else {
+            logger.error("Not supported protocoltype: {}", protocolType);
             throw new IllegalArgumentException("Not handeled protocolversion: " + protocolType);
         }
-
     }
 
     @Override
@@ -135,7 +147,6 @@ public class CcsdkA1AdapterClient implements A1Client {
                     .flatMapMany(A1AdapterJsonHelper::parseJsonArrayOfString) //
                     .collectList();
         }
-
     }
 
     @Override
@@ -162,7 +173,7 @@ public class CcsdkA1AdapterClient implements A1Client {
         } else if (this.protocolType == A1ProtocolType.CCSDK_A1_ADAPTER_STD_V2_0_0) {
             return StdA1ClientVersion2.extractPolicySchema(controllerResponse, policyTypeId);
         } else {
-            throw new NullPointerException("Not supported");
+            return Mono.error(new ServiceException("Not supported " + this.protocolType));
         }
     }
 
@@ -223,6 +234,7 @@ public class CcsdkA1AdapterClient implements A1Client {
         } else if (protocolType == A1ProtocolType.CCSDK_A1_ADAPTER_OSC_V1) {
             return new OscA1Client.UriBuilder(ricConfig);
         }
+        logger.error("Not supported protocoltype: {}", protocolType);
         throw new NullPointerException();
     }
 
@@ -265,29 +277,27 @@ public class CcsdkA1AdapterClient implements A1Client {
     }
 
     private Mono<String> post(String rpcName, String ricUrl, Optional<String> body) {
-        AdapterRequest inputParams = ImmutableAdapterRequest.builder() //
-                .nearRtRicUrl(ricUrl) //
-                .body(body) //
-                .build();
+        AdapterRequest inputParams = new AdapterRequest(ricUrl, body.isPresent() ? body.get() : null);
+
         final String inputJsonString = A1AdapterJsonHelper.createInputJsonString(inputParams);
         logger.debug("POST inputJsonString = {}", inputJsonString);
 
         return restClient
-                .postWithAuthHeader(controllerUrl(rpcName), inputJsonString, this.controllerConfig.userName(),
-                        this.controllerConfig.password()) //
-                .flatMap(this::extractResponseBody);
+                .postWithAuthHeader(controllerUrl(rpcName), inputJsonString, this.controllerConfig.getUserName(),
+                        this.controllerConfig.getPassword()) //
+                .flatMap(resp -> extractResponseBody(resp, ricUrl));
     }
 
-    private Mono<String> extractResponse(JSONObject responseOutput) {
-        AdapterOutput output = gson.fromJson(responseOutput.toString(), ImmutableAdapterOutput.class);
-        Optional<String> optionalBody = output.body();
-        String body = optionalBody.isPresent() ? optionalBody.get() : "";
-        if (HttpStatus.valueOf(output.httpStatus()).is2xxSuccessful()) {
+    private Mono<String> extractResponse(JSONObject responseOutput, String ricUrl) {
+        AdapterOutput output = gson.fromJson(responseOutput.toString(), AdapterOutput.class);
+
+        String body = output.body == null ? "" : output.body;
+        if (HttpStatus.valueOf(output.httpStatus).is2xxSuccessful()) {
             return Mono.just(body);
         } else {
-            logger.debug("Error response: {} {}", output.httpStatus(), body);
+            logger.debug("Error response: {} {}, from: {}", output.httpStatus, body, ricUrl);
             byte[] responseBodyBytes = body.getBytes(StandardCharsets.UTF_8);
-            HttpStatus httpStatus = HttpStatus.valueOf(output.httpStatus());
+            HttpStatus httpStatus = HttpStatus.valueOf(output.httpStatus);
             WebClientResponseException responseException = new WebClientResponseException(httpStatus.value(),
                     httpStatus.getReasonPhrase(), null, responseBodyBytes, StandardCharsets.UTF_8, null);
 
@@ -295,9 +305,9 @@ public class CcsdkA1AdapterClient implements A1Client {
         }
     }
 
-    private Mono<String> extractResponseBody(String responseStr) {
+    private Mono<String> extractResponseBody(String responseStr, String ricUrl) {
         return A1AdapterJsonHelper.getOutput(responseStr) //
-                .flatMap(this::extractResponse);
+                .flatMap(responseOutput -> extractResponse(responseOutput, ricUrl));
     }
 
     private String controllerUrl(String rpcName) {
index 78a418a..dfe33e7 100644 (file)
@@ -110,7 +110,7 @@ public class OscA1Client implements A1Client {
         }
 
         private String baseUri() {
-            return ricConfig.baseUrl() + "/a1-p";
+            return ricConfig.getBaseUrl() + "/a1-p";
         }
     }
 
@@ -125,7 +125,7 @@ public class OscA1Client implements A1Client {
 
     public OscA1Client(RicConfig ricConfig, AsyncRestClient restClient) {
         this.restClient = restClient;
-        logger.debug("OscA1Client for ric: {}", ricConfig.ricId());
+        logger.debug("OscA1Client for ric: {}", ricConfig.getRicId());
 
         uri = new UriBuilder(ricConfig);
     }
index 3566aad..fe7c11f 100644 (file)
@@ -47,7 +47,7 @@ public class SecurityContext {
     @Setter
     private Path authTokenFilePath;
 
-    public SecurityContext(@Value("${app.auth-token-file:\"\"}") String authTokenFilename) {
+    public SecurityContext(@Value("${app.auth-token-file:}") String authTokenFilename) {
         if (!authTokenFilename.isEmpty()) {
             this.authTokenFilePath = Path.of(authTokenFilename);
         }
@@ -63,7 +63,7 @@ public class SecurityContext {
         }
         try {
             long lastModified = authTokenFilePath.toFile().lastModified();
-            if (lastModified != this.tokenTimestamp) {
+            if (tokenTimestamp == 0 || lastModified != this.tokenTimestamp) {
                 this.authToken = Files.readString(authTokenFilePath);
                 this.tokenTimestamp = lastModified;
             }
index b158ad2..5eae775 100644 (file)
@@ -75,7 +75,7 @@ public class StdA1ClientVersion1 implements A1Client {
         }
 
         private String baseUri() {
-            return ricConfig.baseUrl() + "/A1-P/v1";
+            return ricConfig.getBaseUrl() + "/A1-P/v1";
         }
 
         private String policiesBaseUri() {
index d0f4da2..0022057 100644 (file)
@@ -41,6 +41,13 @@ import reactor.core.publisher.Mono;
 public class StdA1ClientVersion2 implements A1Client {
     static final int CONCURRENCY_RIC = 1; // How many paralell requests that is sent to one NearRT RIC
 
+    public static class Factory implements A1Client.Factory {
+        @Override
+        public A1Client create(RicConfig ricConfig, AsyncRestClientFactory restClientFactory) {
+            return new StdA1ClientVersion2(ricConfig, restClientFactory);
+        }
+    }
+
     public static class OranV2UriBuilder implements A1UriBuilder {
         private final RicConfig ricConfig;
 
@@ -114,7 +121,7 @@ public class StdA1ClientVersion2 implements A1Client {
         }
 
         private String baseUri() {
-            return ricConfig.baseUrl() + "/A1-P/v2";
+            return ricConfig.getBaseUrl() + "/A1-P/v2";
         }
     }
 
@@ -129,7 +136,7 @@ public class StdA1ClientVersion2 implements A1Client {
 
     public StdA1ClientVersion2(RicConfig ricConfig, AsyncRestClient restClient) {
         this.restClient = restClient;
-        logger.debug("OscA1Client for ric: {}", ricConfig.ricId());
+        logger.debug("OscA1Client for ric: {}", ricConfig.getRicId());
 
         uriBuiler = new OranV2UriBuilder(ricConfig);
     }
index 236d438..0e2294f 100644 (file)
@@ -100,13 +100,13 @@ public class ApplicationConfig {
 
     public WebClientConfig getWebClientConfig() {
         if (this.webClientConfig == null) {
-            HttpProxyConfig httpProxyConfig = ImmutableHttpProxyConfig.builder() //
+            HttpProxyConfig httpProxyConfig = HttpProxyConfig.builder() //
                     .httpProxyHost(this.httpProxyHost) //
                     .httpProxyPort(this.httpProxyPort) //
                     .httpProxyType(ProxyProvider.Proxy.valueOf(this.httpProxyType)) //
                     .build();
 
-            this.webClientConfig = ImmutableWebClientConfig.builder() //
+            this.webClientConfig = WebClientConfig.builder() //
                     .keyStoreType(this.sslKeyStoreType) //
                     .keyStorePassword(this.sslKeyStorePassword) //
                     .keyStore(this.sslKeyStore) //
@@ -156,23 +156,23 @@ public class ApplicationConfig {
             ApplicationConfigParser.ConfigParserResult parserResult) {
 
         Collection<RicConfigUpdate> modifications = new ArrayList<>();
-        this.controllerConfigs = parserResult.controllerConfigs();
+        this.controllerConfigs = parserResult.getControllerConfigs();
 
-        this.dmaapConsumerTopicUrl = parserResult.dmaapConsumerTopicUrl();
-        this.dmaapProducerTopicUrl = parserResult.dmaapProducerTopicUrl();
+        this.dmaapConsumerTopicUrl = parserResult.getDmaapConsumerTopicUrl();
+        this.dmaapProducerTopicUrl = parserResult.getDmaapProducerTopicUrl();
 
         Map<String, RicConfig> newRicConfigs = new HashMap<>();
-        for (RicConfig newConfig : parserResult.ricConfigs()) {
-            RicConfig oldConfig = this.ricConfigs.get(newConfig.ricId());
-            this.ricConfigs.remove(newConfig.ricId());
+        for (RicConfig newConfig : parserResult.getRicConfigs()) {
+            RicConfig oldConfig = this.ricConfigs.get(newConfig.getRicId());
+            this.ricConfigs.remove(newConfig.getRicId());
             if (oldConfig == null) {
-                newRicConfigs.put(newConfig.ricId(), newConfig);
+                newRicConfigs.put(newConfig.getRicId(), newConfig);
                 modifications.add(new RicConfigUpdate(newConfig, RicConfigUpdate.Type.ADDED));
             } else if (!newConfig.equals(oldConfig)) {
                 modifications.add(new RicConfigUpdate(newConfig, RicConfigUpdate.Type.CHANGED));
-                newRicConfigs.put(newConfig.ricId(), newConfig);
+                newRicConfigs.put(newConfig.getRicId(), newConfig);
             } else {
-                newRicConfigs.put(oldConfig.ricId(), oldConfig);
+                newRicConfigs.put(oldConfig.getRicId(), oldConfig);
             }
         }
         for (RicConfig deletedConfig : this.ricConfigs.values()) {
index 726d67f..3990bc7 100644 (file)
@@ -41,8 +41,9 @@ import java.util.Set;
 
 import javax.validation.constraints.NotNull;
 
-import org.immutables.gson.Gson;
-import org.immutables.value.Value;
+import lombok.Builder;
+import lombok.Getter;
+
 import org.json.JSONObject;
 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
 import org.slf4j.Logger;
@@ -63,16 +64,19 @@ public class ApplicationConfigParser {
         this.applicationConfig = applicationConfig;
     }
 
-    @Value.Immutable
-    @Gson.TypeAdapters
-    public interface ConfigParserResult {
-        List<RicConfig> ricConfigs();
+    @Builder
+    @Getter
+    public static class ConfigParserResult {
+        private List<RicConfig> ricConfigs;
 
-        Map<String, ControllerConfig> controllerConfigs();
+        @Builder.Default
+        private Map<String, ControllerConfig> controllerConfigs = new HashMap<>();
 
-        String dmaapConsumerTopicUrl();
+        @Builder.Default
+        private String dmaapConsumerTopicUrl = "";
 
-        String dmaapProducerTopicUrl();
+        @Builder.Default
+        private String dmaapProducerTopicUrl = "";
 
     }
 
@@ -103,7 +107,7 @@ public class ApplicationConfigParser {
         Map<String, ControllerConfig> controllerConfigs = parseControllerConfigs(pmsConfigJson);
         checkConfigurationConsistency(ricConfigs, controllerConfigs);
 
-        return ImmutableConfigParserResult.builder() //
+        return ConfigParserResult.builder() //
                 .dmaapConsumerTopicUrl(dmaapConsumerTopicUrl) //
                 .dmaapProducerTopicUrl(dmaapProducerTopicUrl) //
                 .ricConfigs(ricConfigs) //
@@ -147,15 +151,15 @@ public class ApplicationConfigParser {
         Set<String> ricUrls = new HashSet<>();
         Set<String> ricNames = new HashSet<>();
         for (RicConfig ric : ricConfigs) {
-            if (!ricUrls.add(ric.baseUrl())) {
-                throw new ServiceException("Configuration error, more than one RIC URL: " + ric.baseUrl());
+            if (!ricUrls.add(ric.getBaseUrl())) {
+                throw new ServiceException("Configuration error, more than one RIC URL: " + ric.getBaseUrl());
             }
-            if (!ricNames.add(ric.ricId())) {
-                throw new ServiceException("Configuration error, more than one RIC with name: " + ric.ricId());
+            if (!ricNames.add(ric.getRicId())) {
+                throw new ServiceException("Configuration error, more than one RIC with name: " + ric.getRicId());
             }
-            if (!ric.controllerName().isEmpty() && controllerConfigs.get(ric.controllerName()) == null) {
+            if (!ric.getControllerName().isEmpty() && controllerConfigs.get(ric.getControllerName()) == null) {
                 throw new ServiceException(
-                        "Configuration error, controller configuration not found: " + ric.controllerName());
+                        "Configuration error, controller configuration not found: " + ric.getControllerName());
             }
         }
     }
@@ -163,23 +167,31 @@ public class ApplicationConfigParser {
     private List<RicConfig> parseRics(JsonObject config) throws ServiceException {
         List<RicConfig> result = new ArrayList<>();
         for (JsonElement ricElem : getAsJsonArray(config, "ric")) {
-            JsonObject ricAsJson = ricElem.getAsJsonObject();
-            JsonElement controllerNameElement = ricAsJson.get(CONTROLLER);
-            RicConfig ricConfig = ImmutableRicConfig.builder() //
-                    .ricId(get(ricAsJson, "name", "id", "ricId").getAsString()) //
-                    .baseUrl(get(ricAsJson, "baseUrl").getAsString()) //
-                    .managedElementIds(parseManagedElementIds(get(ricAsJson, "managedElementIds").getAsJsonArray())) //
-                    .controllerName(controllerNameElement != null ? controllerNameElement.getAsString() : "") //
+            JsonObject ricJsonObj = ricElem.getAsJsonObject();
+            RicConfig ricConfig = RicConfig.builder() //
+                    .ricId(get(ricJsonObj, "name", "id", "ricId").getAsString()) //
+                    .baseUrl(get(ricJsonObj, "baseUrl").getAsString()) //
+                    .managedElementIds(parseManagedElementIds(get(ricJsonObj, "managedElementIds").getAsJsonArray())) //
+                    .controllerName(getString(ricJsonObj, CONTROLLER, ""))
+                    .customAdapterClass(getString(ricJsonObj, "customAdapterClass", "")) //
                     .build();
-            if (!ricConfig.baseUrl().isEmpty()) {
+            if (!ricConfig.getBaseUrl().isEmpty()) {
                 result.add(ricConfig);
             } else {
-                logger.error("RIC configuration error {}, baseUrl is empty", ricConfig.ricId());
+                logger.error("RIC configuration error {}, baseUrl is empty", ricConfig.getRicId());
             }
         }
         return result;
     }
 
+    String getString(JsonObject obj, String name, String defaultValue) {
+        JsonElement elem = obj.get(name);
+        if (elem != null) {
+            return elem.getAsString();
+        }
+        return defaultValue;
+    }
+
     Map<String, ControllerConfig> parseControllerConfigs(JsonObject config) throws ServiceException {
         if (config.get(CONTROLLER) == null) {
             return new HashMap<>();
@@ -187,16 +199,16 @@ public class ApplicationConfigParser {
         Map<String, ControllerConfig> result = new HashMap<>();
         for (JsonElement element : getAsJsonArray(config, CONTROLLER)) {
             JsonObject controllerAsJson = element.getAsJsonObject();
-            ImmutableControllerConfig controllerConfig = ImmutableControllerConfig.builder() //
+            ControllerConfig controllerConfig = ControllerConfig.builder() //
                     .name(get(controllerAsJson, "name").getAsString()) //
                     .baseUrl(get(controllerAsJson, "baseUrl").getAsString()) //
                     .password(get(controllerAsJson, "password").getAsString()) //
                     .userName(get(controllerAsJson, "userName").getAsString()) // )
                     .build();
 
-            if (result.put(controllerConfig.name(), controllerConfig) != null) {
+            if (result.put(controllerConfig.getName(), controllerConfig) != null) {
                 throw new ServiceException(
-                        "Configuration error, more than one controller with name: " + controllerConfig.name());
+                        "Configuration error, more than one controller with name: " + controllerConfig.getName());
             }
         }
         return result;
index 5f00cf6..1c52edc 100644 (file)
 
 package org.onap.ccsdk.oran.a1policymanagementservice.configuration;
 
-import org.immutables.value.Value;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
 
-@Value.Immutable
-@Value.Style(redactedMask = "####")
+@Builder
+@Getter
+@EqualsAndHashCode
+@ToString
+public class ControllerConfig {
+    private String name;
 
-public interface ControllerConfig {
-    public String name();
+    private String baseUrl;
 
-    public String baseUrl();
-
-    public String userName();
-
-    @Value.Redacted
-    public String password();
+    private String userName;
 
+    @ToString.Exclude
+    private String password;
 }
index 7f7f9f5..ffe853f 100644 (file)
 
 package org.onap.ccsdk.oran.a1policymanagementservice.configuration;
 
-import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.Collection;
 
-import org.immutables.value.Value;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
 
-@Value.Immutable
-public interface RicConfig {
-    public String ricId();
+@Builder
+@Getter
+@EqualsAndHashCode
+@ToString
+public class RicConfig {
+    private String ricId;
 
-    public String controllerName();
+    @Builder.Default
+    private String controllerName = "";
 
-    public String baseUrl();
+    private String baseUrl;
 
-    public ImmutableList<String> managedElementIds();
+    @Builder.Default
+    private Collection<String> managedElementIds = new ArrayList<>();
 
+    @Builder.Default
+    private String customAdapterClass = "";
 }
index 1e5d7ff..e71f855 100644 (file)
 
 package org.onap.ccsdk.oran.a1policymanagementservice.configuration;
 
-import org.immutables.value.Value;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.ToString;
 import reactor.netty.transport.ProxyProvider;
 
-@Value.Immutable
-@Value.Style(redactedMask = "####")
-public interface WebClientConfig {
-    public String keyStoreType();
+@Builder
+@Getter
+@ToString
+public class WebClientConfig {
+    private String keyStoreType;
 
-    @Value.Redacted
-    public String keyStorePassword();
+    private String keyStorePassword;
 
-    public String keyStore();
+    private String keyStore;
 
-    @Value.Redacted
-    public String keyPassword();
+    @ToString.Exclude
+    private String keyPassword;
 
-    public boolean isTrustStoreUsed();
+    private boolean isTrustStoreUsed;
 
-    @Value.Redacted
-    public String trustStorePassword();
+    private String trustStorePassword;
 
-    public String trustStore();
+    private String trustStore;
 
-    @Value.Immutable
-    public interface HttpProxyConfig {
-        public String httpProxyHost();
+    @Builder
+    @Getter
+    @ToString
+    public static class HttpProxyConfig {
+        private String httpProxyHost;
 
-        public int httpProxyPort();
+        private int httpProxyPort;
 
-        public ProxyProvider.Proxy httpProxyType();
+        private ProxyProvider.Proxy httpProxyType;
     }
 
-    public HttpProxyConfig httpProxyConfig();
+    private HttpProxyConfig httpProxyConfig;
 
 }
index 7d89206..c5436cd 100644 (file)
@@ -25,9 +25,6 @@ import com.google.gson.annotations.SerializedName;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "service_callback_info_v2",
         description = "Information transferred as in Service callbacks (callback_url)")
 public class ServiceCallbackInfo {
@@ -35,7 +32,6 @@ public class ServiceCallbackInfo {
     private static final String EVENT_TYPE_DESCRIPTION = "values:\n" //
             + "AVAILABLE: the  Near-RT RIC has become available for A1 Policy management";
 
-    @Gson.TypeAdapters
     @Schema(name = "event_type_v2", description = EVENT_TYPE_DESCRIPTION)
     public enum EventType {
         AVAILABLE
index 754d169..6470abf 100644 (file)
@@ -22,9 +22,6 @@ package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "void", description = "Void/empty")
 public class VoidResponse {
     private VoidResponse() {}
index 6201842..500ddd2 100644 (file)
@@ -66,6 +66,7 @@ import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.reactive.function.client.WebClientException;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
 import reactor.core.publisher.Mono;
 
@@ -277,6 +278,9 @@ public class PolicyController {
         if (throwable instanceof WebClientResponseException) {
             WebClientResponseException e = (WebClientResponseException) throwable;
             return ErrorResponse.createMono(e.getResponseBodyAsString(), e.getStatusCode());
+        } else if (throwable instanceof WebClientException) {
+            WebClientException e = (WebClientException) throwable;
+            return ErrorResponse.createMono(e.getMessage(), HttpStatus.BAD_GATEWAY);
         } else if (throwable instanceof RejectionException) {
             RejectionException e = (RejectionException) throwable;
             return ErrorResponse.createMono(e.getMessage(), e.getStatus());
index cc9b83a..4e55c50 100644 (file)
@@ -27,9 +27,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 
 import java.util.Collection;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "policy_id_list_v2", description = "A list of policy identities")
 public class PolicyIdList {
 
index 2e19a3d..55a9343 100644 (file)
@@ -25,9 +25,6 @@ import com.google.gson.annotations.SerializedName;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "policy_info_v2", description = "Information for one A1-P Policy")
 public class PolicyInfo {
 
index 08923fd..04f7e1e 100644 (file)
@@ -27,9 +27,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 
 import java.util.Collection;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "policy_info_list_v2", description = "List of policy information")
 public class PolicyInfoList {
 
index bc95e54..c19c4a0 100644 (file)
@@ -27,9 +27,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 
 import java.time.Instant;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "policy_status_info_v2", description = "Status for one A1-P Policy")
 public class PolicyStatusInfo {
 
index deedf2f..c2610b0 100644 (file)
@@ -27,9 +27,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 
 import java.util.Collection;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "policytype_id_list_v2", description = "Information about policy types")
 public class PolicyTypeIdList {
 
index b619e44..591c1ca 100644 (file)
@@ -27,9 +27,6 @@ import com.google.gson.annotations.SerializedName;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "policytype_v2", description = "Policy type")
 public class PolicyTypeInfo {
 
index 38797ca..4492770 100644 (file)
@@ -27,13 +27,9 @@ import io.swagger.v3.oas.annotations.media.Schema;
 
 import java.util.Collection;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "ric_info_v2", description = "Information for a Near-RT RIC")
 public class RicInfo {
 
-    @Gson.TypeAdapters
     @Schema(name = "ric_state_v2", description = "Represents the states for a Near-RT RIC")
     public enum RicState {
         UNAVAILABLE, AVAILABLE, SYNCHRONIZING, CONSISTENCY_CHECK
index 05b9569..f5612f9 100644 (file)
@@ -27,9 +27,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 
 import java.util.Collection;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "ric_info_list_v2", description = "List of Near-RT RIC information")
 public class RicInfoList {
 
index 17277c9..0f975c2 100644 (file)
@@ -25,9 +25,6 @@ import com.google.gson.annotations.SerializedName;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "service_registration_info_v2", description = "Information for one service")
 public class ServiceRegistrationInfo {
 
index 981c95b..e6aa8d4 100644 (file)
@@ -27,9 +27,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 
 import java.util.Collection;
 
-import org.immutables.gson.Gson;
-
-@Gson.TypeAdapters
 @Schema(name = "service_list_v2", description = "List of service information")
 public class ServiceStatusList {
 
index df9dfd1..28d434b 100644 (file)
@@ -27,7 +27,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.tags.Tag;
 
-import org.immutables.gson.Gson;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
@@ -45,7 +44,6 @@ public class StatusController {
     public static final String API_NAME = "Health Check";
     public static final String API_DESCRIPTION = "";
 
-    @Gson.TypeAdapters
     @Schema(name = "status_info_v2")
     class StatusInfo {
         @Schema(description = "status text")
index f43737f..2971feb 100644 (file)
@@ -30,17 +30,20 @@ import lombok.Setter;
 
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Holds information about a Near-RT RIC.
  */
 public class Ric {
+    private static final Logger logger = LoggerFactory.getLogger(Ric.class);
 
     @Setter
     private RicConfig ricConfig;
     private RicState state = RicState.UNAVAILABLE;
     private Map<String, PolicyType> supportedPolicyTypes = new HashMap<>();
-    @Getter
+
     @Setter
     private A1ProtocolType protocolVersion = A1ProtocolType.UNKNOWN;
 
@@ -54,11 +57,11 @@ public class Ric {
      */
     public Ric(RicConfig ricConfig) {
         this.ricConfig = ricConfig;
-        this.lock = new Lock(ricConfig.ricId());
+        this.lock = new Lock(ricConfig.getRicId());
     }
 
     public String id() {
-        return ricConfig.ricId();
+        return ricConfig.getRicId();
     }
 
     public RicConfig getConfig() {
@@ -70,16 +73,25 @@ public class Ric {
     }
 
     public synchronized void setState(RicState state) {
+        logger.debug("Ric {} state set to {}", getConfig().getRicId(), state);
         this.state = state;
     }
 
+    public synchronized A1ProtocolType getProtocolVersion() {
+        if (this.ricConfig.getCustomAdapterClass().isEmpty()) {
+            return this.protocolVersion;
+        } else {
+            return A1ProtocolType.CUSTOM_PROTOCOL;
+        }
+    }
+
     /**
      * Gets the nodes managed by this Ric.
      *
      * @return a vector containing the nodes managed by this Ric.
      */
     public synchronized Collection<String> getManagedElementIds() {
-        return new Vector<>(ricConfig.managedElementIds());
+        return new Vector<>(ricConfig.getManagedElementIds());
     }
 
     /**
@@ -89,7 +101,7 @@ public class Ric {
      * @return true if the given node is managed by this Ric.
      */
     public synchronized boolean isManaging(String managedElementId) {
-        return ricConfig.managedElementIds().contains(managedElementId);
+        return ricConfig.getManagedElementIds().contains(managedElementId);
     }
 
     /**
@@ -135,7 +147,7 @@ public class Ric {
     @Override
     public synchronized String toString() {
         return Ric.class.getSimpleName() + ": " + "name: " + id() + ", state: " + state + ", baseUrl: "
-                + ricConfig.baseUrl() + ", managedNodes: " + ricConfig.managedElementIds();
+                + ricConfig.getBaseUrl() + ", managedNodes: " + ricConfig.getManagedElementIds();
     }
 
     /**
index e3d489b..983e92e 100644 (file)
@@ -36,11 +36,9 @@ import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationCo
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig.RicConfigUpdate;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfigParser;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ConfigurationFile;
-import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceCallbacks;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
-import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
 import org.slf4j.Logger;
@@ -130,7 +128,7 @@ public class RefreshConfigTask {
                 .flatMap(this::parseConfiguration) //
                 .flatMap(this::updateConfig, CONCURRENCY) //
                 .flatMap(this::handleUpdatedRicConfig) //
-                .doOnTerminate(() -> logger.error("Configuration refresh task is terminated"));
+                .doFinally(signal -> logger.error("Configuration refresh task is terminated: {}", signal));
     }
 
     private Flux<Long> regularInterval() {
@@ -170,40 +168,16 @@ public class RefreshConfigTask {
         return new RicSynchronizationTask(a1ClientFactory, policyTypes, policies, services, restClientFactory, rics);
     }
 
-    /**
-     * for an added RIC after a restart it is nesessary to get the suypported policy
-     * types from the RIC unless a full synchronization is wanted.
-     *
-     * @param ric the ric to get supprted types from
-     * @return the same ric
-     */
-    private Mono<Ric> trySyncronizeSupportedTypes(Ric ric) {
-        logger.debug("Synchronizing policy types for new RIC: {}", ric.id());
-        // Synchronize the policy types
-        ric.setState(RicState.SYNCHRONIZING);
-        return this.a1ClientFactory.createA1Client(ric) //
-                .flatMapMany(client -> synchronizationTask().synchronizePolicyTypes(ric, client)) //
-                .collectList() //
-                .map(list -> ric) //
-                .doOnNext(notUsed -> ric.setState(RicState.AVAILABLE)) //
-                .doOnError(t -> {
-                    logger.warn("Failed to synchronize types in new RIC: {}, reason: {}", ric.id(), t.getMessage());
-                    ric.setState(RicState.UNAVAILABLE); //
-                }) //
-                .onErrorResume(t -> Mono.just(ric));
-    }
-
     public Mono<RicConfigUpdate.Type> handleUpdatedRicConfig(RicConfigUpdate updatedInfo) {
         synchronized (this.rics) {
-            String ricId = updatedInfo.getRicConfig().ricId();
+            String ricId = updatedInfo.getRicConfig().getRicId();
             RicConfigUpdate.Type event = updatedInfo.getType();
             if (event == RicConfigUpdate.Type.ADDED) {
                 logger.debug("RIC added {}", ricId);
-
-                return trySyncronizeSupportedTypes(new Ric(updatedInfo.getRicConfig())) //
-                        .doOnNext(this::addRic) //
-                        .flatMap(this::notifyServicesRicAvailable) //
-                        .flatMap(notUsed -> Mono.just(event));
+                Ric ric = new Ric(updatedInfo.getRicConfig());
+                this.addRic(ric);
+                return this.synchronizationTask().synchronizeRic(ric) //
+                        .map(notUsed -> event);
             } else if (event == RicConfigUpdate.Type.REMOVED) {
                 logger.debug("RIC removed {}", ricId);
                 Ric ric = rics.remove(ricId);
@@ -231,17 +205,6 @@ public class RefreshConfigTask {
         logger.debug("Added RIC: {}", ric.id());
     }
 
-    private Mono<Ric> notifyServicesRicAvailable(Ric ric) {
-        if (ric.getState() == RicState.AVAILABLE) {
-            ServiceCallbacks callbacks = new ServiceCallbacks(this.restClientFactory);
-            return callbacks.notifyServicesRicAvailable(ric, services) //
-                    .collectList() //
-                    .map(list -> ric);
-        } else {
-            return Mono.just(ric);
-        }
-    }
-
     /**
      * Reads the configuration from file.
      */
index 8926ec1..e3edaf4 100644 (file)
@@ -64,11 +64,11 @@ public class RicSupervision {
     private final Services services;
     private final AsyncRestClientFactory restClientFactory;
 
-    private static class SynchStartedException extends ServiceException {
+    private static class SynchNeededException extends ServiceException {
         private static final long serialVersionUID = 1L;
 
-        public SynchStartedException(String message) {
-            super(message);
+        public SynchNeededException(RicData ric) {
+            super("SynchNeededException for " + ric.ric.id());
         }
     }
 
@@ -106,68 +106,61 @@ public class RicSupervision {
         createTask().subscribe(null, null, () -> logger.debug("Checking all RICs completed"));
     }
 
-    private Flux<RicData> createTask() {
+    private Flux<Ric> createTask() {
         return Flux.fromIterable(rics.getRics()) //
                 .flatMap(this::createRicData) //
-                .flatMap(this::checkOneRic, CONCURRENCY);
+                .onErrorResume(t -> Flux.empty()) //
+                .flatMap(this::checkOneRic, CONCURRENCY) //
+                .map(ricData -> ricData.ric);
     }
 
     private Mono<RicData> checkOneRic(RicData ricData) {
-        return checkRicState(ricData) //
-                .flatMap(x -> ricData.ric.getLock().lock(LockType.EXCLUSIVE, "checkOneRic")) //
-                .flatMap(notUsed -> setRicState(ricData)) //
+        if (ricData.ric.getState() == RicState.CONSISTENCY_CHECK || ricData.ric.getState() == RicState.SYNCHRONIZING) {
+            logger.debug("Skipping check ric: {}, state: {}", ricData.ric.id(), ricData.ric.getState());
+            return Mono.empty(); // Skip, already in progress
+        }
+        return ricData.ric.getLock().lock(LockType.EXCLUSIVE, "checkOneRic") //
+                .flatMap(lock -> synchIfUnavailable(ricData)) //
+                .doOnNext(ric -> ricData.ric.setState(RicState.CONSISTENCY_CHECK)) //
                 .flatMap(x -> checkRicPolicies(ricData)) //
                 .flatMap(x -> checkRicPolicyTypes(ricData)) //
                 .doOnNext(x -> onRicCheckedOk(ricData)) //
-                .doOnError(t -> onRicCheckedError(t, ricData)) //
+                .onErrorResume(t -> onRicCheckedError(t, ricData)) //
+                .doFinally(sig -> ricData.ric.getLock().unlockBlocking()) //
                 .onErrorResume(throwable -> Mono.empty());
     }
 
-    private void onRicCheckedError(Throwable t, RicData ricData) {
+    private Mono<RicData> synchIfUnavailable(RicData ric) {
+        if (ric.ric.getState() == RicState.UNAVAILABLE) {
+            return Mono.error(new SynchNeededException(ric));
+        } else {
+            return Mono.just(ric);
+        }
+    }
+
+    private Mono<RicData> onRicCheckedError(Throwable t, RicData ricData) {
         logger.debug("Ric: {} check stopped, exception: {}", ricData.ric.id(), t.getMessage());
-        if (!(t instanceof SynchStartedException)) {
-            // If synch is started, the synch will set the final state
-            ricData.ric.setState(RicState.UNAVAILABLE);
+        ricData.ric.setState(RicState.UNAVAILABLE);
+        if ((t instanceof SynchNeededException)) {
+            return startSynchronization(ricData);
+        } else {
+            logger.warn("RicSupervision, ric: {}, exception: {}", ricData.ric.id(), t.getMessage());
+            return Mono.empty();
         }
-        ricData.ric.getLock().unlockBlocking();
     }
 
     private void onRicCheckedOk(RicData ricData) {
         logger.debug("Ric: {} checked OK", ricData.ric.id());
         ricData.ric.setState(RicState.AVAILABLE);
-        ricData.ric.getLock().unlockBlocking();
-    }
-
-    @SuppressWarnings("squid:S2445") // Blocks should be synchronized on "private final" fields
-    private Mono<RicData> setRicState(RicData ric) {
-        synchronized (ric) {
-            if (ric.ric.getState() == RicState.CONSISTENCY_CHECK) {
-                logger.debug("Ric: {} is already being checked", ric.ric.getConfig().ricId());
-                return Mono.empty();
-            }
-            ric.ric.setState(RicState.CONSISTENCY_CHECK);
-            return Mono.just(ric);
-        }
     }
 
     private Mono<RicData> createRicData(Ric ric) {
-        return Mono.just(ric) //
-                .flatMap(aRic -> this.a1ClientFactory.createA1Client(ric)) //
+        return this.a1ClientFactory.createA1Client(ric) //
+                .doOnError(t -> logger.debug("Could not create A1 client for ric: {}, reason: {}", ric.id(),
+                        t.getMessage())) //
                 .map(a1Client -> new RicData(ric, a1Client));
     }
 
-    private Mono<RicData> checkRicState(RicData ric) {
-        if (ric.ric.getState() == RicState.UNAVAILABLE) {
-            logger.debug("RicSupervision, starting ric: {} synchronization (state == UNAVAILABLE)", ric.ric.id());
-            return startSynchronization(ric) //
-                    .onErrorResume(t -> Mono.empty());
-        } else if (ric.ric.getState() == RicState.SYNCHRONIZING || ric.ric.getState() == RicState.CONSISTENCY_CHECK) {
-            return Mono.empty();
-        } else {
-            return Mono.just(ric);
-        }
-    }
-
     private Mono<RicData> checkRicPolicies(RicData ric) {
         return ric.getClient().getPolicyIdentities() //
                 .flatMap(ricP -> validateInstances(ricP, ric));
@@ -178,14 +171,14 @@ public class RicSupervision {
             if (ricPolicies.size() != policies.getForRic(ric.ric.id()).size()) {
                 logger.debug("RicSupervision, starting ric: {} synchronization (noOfPolicices == {}, expected == {})",
                         ric.ric.id(), ricPolicies.size(), policies.getForRic(ric.ric.id()).size());
-                return startSynchronization(ric);
+                return Mono.error(new SynchNeededException(ric));
             }
 
             for (String policyId : ricPolicies) {
                 if (!policies.containsPolicy(policyId)) {
                     logger.debug("RicSupervision, starting ric: {} synchronization (unexpected policy in RIC: {})",
                             ric.ric.id(), policyId);
-                    return startSynchronization(ric);
+                    return Mono.error(new SynchNeededException(ric));
                 }
             }
             return Mono.just(ric);
@@ -202,22 +195,23 @@ public class RicSupervision {
             logger.debug(
                     "RicSupervision, starting ric: {} synchronization (unexpected numer of policy types in RIC: {}, expected: {})",
                     ric.ric.id(), ricTypes.size(), ric.ric.getSupportedPolicyTypes().size());
-            return startSynchronization(ric);
+            return Mono.error(new SynchNeededException(ric));
         }
         for (String typeName : ricTypes) {
             if (!ric.ric.isSupportingType(typeName)) {
                 logger.debug("RicSupervision, starting ric: {} synchronization (unexpected policy type: {})",
                         ric.ric.id(), typeName);
-                return startSynchronization(ric);
+                return Mono.error(new SynchNeededException(ric));
             }
         }
         return Mono.just(ric);
     }
 
     private Mono<RicData> startSynchronization(RicData ric) {
+        logger.debug("RicSupervision, starting ric: {} synchronization, state: {}", ric.ric.id(), ric.ric.getState());
         RicSynchronizationTask synchronizationTask = createSynchronizationTask();
         return synchronizationTask.synchronizeRic(ric.ric) //
-                .flatMap(notUsed -> Mono.error(new SynchStartedException("Syncronization started")));
+                .flatMap(notUsed -> Mono.just(ric));
 
     }
 
index 6305abf..b3afa7c 100644 (file)
@@ -36,8 +36,8 @@ import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
 
-import reactor.core.publisher.BaseSubscriber;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.SignalType;
@@ -78,61 +78,69 @@ public class RicSynchronizationTask {
     }
 
     public void run(Ric ric) {
-        logger.debug("Ric synchronization task created: {}", ric.getConfig().ricId());
+        logger.debug("Ric synchronization task created: {}", ric.getConfig().getRicId());
 
         if (ric.getState() == RicState.SYNCHRONIZING) {
-            logger.debug("Ric: {} is already being synchronized", ric.getConfig().ricId());
+            logger.debug("Ric: {} is already being synchronized", ric.getConfig().getRicId());
             return;
         }
 
         ric.getLock().lock(LockType.EXCLUSIVE, "RicSynchronizationTask") //
                 .flatMap(notUsed -> synchronizeRic(ric)) //
-                .subscribe(new BaseSubscriber<Object>() {
-
-                    @Override
-                    protected void hookFinally(SignalType type) {
-                        ric.getLock().unlockBlocking();
-                    }
-                });
+                .doFinally(sig -> ric.getLock().unlockBlocking()) //
+                .subscribe();
     }
 
     public Mono<Ric> synchronizeRic(Ric ric) {
-        return setRicState(ric) //
-                .flatMap(lock -> this.a1ClientFactory.createA1Client(ric)) //
+        return this.a1ClientFactory.createA1Client(ric) //
+                .doOnNext(client -> ric.setState(RicState.SYNCHRONIZING)) //
                 .flatMapMany(client -> runSynchronization(ric, client)) //
-                .onErrorResume(throwable -> deleteAllPolicyInstances(ric, throwable)) //
-                .collectList() //
-                .map(notUsed -> ric) //
                 .doOnError(t -> { //
                     logger.warn("Synchronization failure for ric: {}, reason: {}", ric.id(), t.getMessage()); //
-                    ric.setState(RicState.UNAVAILABLE); //
+                    deletePoliciesIfNotRecreatable(t, ric);
                 }) //
+                .collectList() //
                 .flatMap(notUsed -> onSynchronizationComplete(ric)) //
-                .onErrorResume(t -> Mono.just(ric));
+                .onErrorResume(t -> Mono.just(ric)) //
+                .doFinally(signal -> onFinally(signal, ric));
+    }
+
+    private void onFinally(SignalType signal, Ric ric) {
+        if (ric.getState().equals(RicState.SYNCHRONIZING)) {
+            logger.debug("Resetting ric state after failed synch, ric: {}, signal: {}", ric.id(), signal);
+            ric.setState(RicState.UNAVAILABLE); //
+        }
+    }
+
+    /**
+     * If a 4xx error is received, allpolicies are deleted. This is just to avoid
+     * cyclical receovery due to that the NearRT RIC cannot accept a previously
+     * policy.
+     */
+    private void deletePoliciesIfNotRecreatable(Throwable throwable, Ric ric) {
+        if (throwable instanceof WebClientResponseException) {
+            WebClientResponseException responseException = (WebClientResponseException) throwable;
+            if (responseException.getStatusCode().is4xxClientError()) {
+                deleteAllPoliciesInRepository(ric);
+            }
+        }
+    }
+
+    private void deleteAllPoliciesInRepository(Ric ric) {
+        for (Policy policy : policies.getForRic(ric.id())) {
+            this.policies.remove(policy);
+        }
     }
 
     public Flux<PolicyType> synchronizePolicyTypes(Ric ric, A1Client a1Client) {
         return a1Client.getPolicyTypeIdentities() //
                 .doOnNext(x -> ric.clearSupportedPolicyTypes()) //
                 .flatMapMany(Flux::fromIterable) //
-                .doOnNext(typeId -> logger.debug("For ric: {}, handling type: {}", ric.getConfig().ricId(), typeId)) //
+                .doOnNext(typeId -> logger.debug("For ric: {}, handling type: {}", ric.getConfig().getRicId(), typeId)) //
                 .flatMap(policyTypeId -> getPolicyType(policyTypeId, a1Client), CONCURRENCY_RIC) //
                 .doOnNext(ric::addSupportedPolicyType); //
     }
 
-    @SuppressWarnings("squid:S2445") // Blocks should be synchronized on "private final" fields
-    private Mono<Ric> setRicState(Ric ric) {
-        synchronized (ric) {
-            if (ric.getState() == RicState.SYNCHRONIZING) {
-                logger.debug("Ric: {} is already being synchronized", ric.getConfig().ricId());
-                return Mono.empty();
-            }
-            logger.debug("Ric state set to SYNCHRONIZING: {}", ric.getConfig().ricId());
-            ric.setState(RicState.SYNCHRONIZING);
-            return Mono.just(ric);
-        }
-    }
-
     private Flux<Object> runSynchronization(Ric ric, A1Client a1Client) {
         Flux<PolicyType> synchronizedTypes = synchronizePolicyTypes(ric, a1Client);
         Flux<?> policiesDeletedInRic = a1Client.deleteAllPolicies();
@@ -154,19 +162,6 @@ public class RicSynchronizationTask {
                 .map(list -> ric);
     }
 
-    private Flux<Object> deleteAllPolicyInstances(Ric ric, Throwable t) {
-        logger.warn("Recreation of policies failed for ric: {}, reason: {}", ric.id(), t.getMessage());
-        deleteAllPoliciesInRepository(ric);
-
-        Flux<PolicyType> synchronizedTypes = this.a1ClientFactory.createA1Client(ric) //
-                .flatMapMany(a1Client -> synchronizePolicyTypes(ric, a1Client));
-        Flux<?> deletePoliciesInRic = this.a1ClientFactory.createA1Client(ric) //
-                .flatMapMany(A1Client::deleteAllPolicies) //
-                .doOnComplete(() -> deleteAllPoliciesInRepository(ric));
-
-        return Flux.concat(synchronizedTypes, deletePoliciesInRic);
-    }
-
     private Mono<PolicyType> getPolicyType(String policyTypeId, A1Client a1Client) {
         if (policyTypes.contains(policyTypeId)) {
             return Mono.just(policyTypes.get(policyTypeId));
@@ -181,14 +176,8 @@ public class RicSynchronizationTask {
         return pt;
     }
 
-    private void deleteAllPoliciesInRepository(Ric ric) {
-        for (Policy policy : policies.getForRic(ric.id())) {
-            this.policies.remove(policy);
-        }
-    }
-
     private Flux<Policy> putPolicy(Policy policy, Ric ric, A1Client a1Client) {
-        logger.trace("Recreating policy: {}, for ric: {}", policy.getId(), ric.getConfig().ricId());
+        logger.trace("Recreating policy: {}, for ric: {}", policy.getId(), ric.getConfig().getRicId());
         return a1Client.putPolicy(policy) //
                 .flatMapMany(notUsed -> Flux.just(policy));
     }
index 05135e7..947db33 100644 (file)
@@ -54,6 +54,9 @@
                 },
                 "controller": {
                   "type": "string"
+                }, 
+                "customAdapterClass" : {
+                  "type": "string"
                 },
                 "managedElementIds": {
                   "type": "array",
                   },
                   "required": [
                     "topic_url"
-                  ]
+                  ],
+                  "additionalProperties": false
                 }
               },
               "required": [
                 "type",
                 "dmaap_info"
-              ]
+              ],
+              "additionalProperties": false
             }
           },
           "required": [
             "dmaap_publisher"
-          ]
+          ],
+           "additionalProperties": false
         },
         "streams_subscribes": {
           "type": "object",
                   },
                   "required": [
                     "topic_url"
-                  ]
+                  ],
+                  "additionalProperties": false
                 }
               },
               "required": [
                 "type",
                 "dmaap_info"
-              ]
+              ],
+               "additionalProperties": false
             }
           },
           "required": [
             "dmaap_subscriber"
-          ]
+          ],
+           "additionalProperties": false
         }
       },
       "required": [
   "required": [
     "config"
   ]
-}
\ No newline at end of file
+}
index 3cb1d91..3b7695e 100644 (file)
@@ -32,7 +32,6 @@ import java.nio.file.Files;
 import java.time.Instant;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
@@ -50,10 +49,8 @@ import org.springframework.boot.test.context.TestConfiguration;
 import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.context.annotation.Bean;
 import org.springframework.test.context.TestPropertySource;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.util.StringUtils;
 
-@ExtendWith(SpringExtension.class)
 @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
 @TestPropertySource(properties = { //
         "server.ssl.key-store=./config/keystore.jks", //
index 645f235..424668f 100644 (file)
@@ -27,8 +27,7 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
-import java.util.Vector;
-
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -37,8 +36,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableControllerConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
 
@@ -68,21 +66,24 @@ class A1ClientFactoryTest {
     private Ric ric;
     private A1ClientFactory factoryUnderTest;
 
-    private static ImmutableRicConfig ricConfig(String controllerName) {
-        return ImmutableRicConfig.builder() //
+    private static RicConfig ricConfig(String controllerName, String customAdapter) {
+        return RicConfig.builder() //
                 .ricId(RIC_NAME) //
                 .baseUrl("baseUrl") //
-                .managedElementIds(new Vector<>()) //
                 .controllerName(controllerName) //
+                .customAdapterClass(customAdapter) //
                 .build();
     }
 
+    private static RicConfig ricConfig(String controllerName) {
+        return ricConfig(controllerName, "");
+    }
+
     @BeforeEach
     void createFactoryUnderTest() {
         SecurityContext sec = new SecurityContext("");
         factoryUnderTest = spy(new A1ClientFactory(applicationConfigMock, sec));
         this.ric = new Ric(ricConfig(""));
-
     }
 
     @Test
@@ -109,6 +110,38 @@ class A1ClientFactoryTest {
         assertEquals(A1ProtocolType.STD_V1_1, ric.getProtocolVersion(), "Not correct protocol");
     }
 
+    public static class CustomA1AdapterFactory implements A1Client.Factory {
+        @Override
+        public A1Client create(RicConfig ricConfig, AsyncRestClientFactory restClientFactory) {
+            return new StdA1ClientVersion2(ricConfig, restClientFactory);
+        }
+    }
+
+    @Test
+    void testCustomAdapterCreation() {
+
+        Ric ric = new Ric(ricConfig("", CustomA1AdapterFactory.class.getName()));
+        A1Client client = factoryUnderTest.createA1Client(ric).block();
+
+        assertEquals(client.getClass(), StdA1ClientVersion2.class);
+
+        ric = new Ric(ricConfig("", "org.onap.ccsdk.oran.a1policymanagementservice.clients.StdA1ClientVersion2"));
+        client = factoryUnderTest.createA1Client(ric).block();
+
+        assertEquals(client.getClass(), StdA1ClientVersion2.class);
+
+        ric = new Ric(
+                ricConfig("", "org.onap.ccsdk.oran.a1policymanagementservice.clients.StdA1ClientVersion2$Factory"));
+        client = factoryUnderTest.createA1Client(ric).block();
+
+        assertEquals(client.getClass(), StdA1ClientVersion2.class);
+
+        Exception e = Assertions.assertThrows(Exception.class, () -> {
+            factoryUnderTest.createClient(new Ric(ricConfig("", "junk")), A1ProtocolType.CUSTOM_PROTOCOL);
+        });
+        assertEquals("Could not find class: junk", e.getMessage());
+    }
+
     @Test
     void getProtocolVersion_error() throws ServiceException {
         whenGetProtocolVersionThrowException(clientMock1, clientMock2, clientMock3, clientMock4);
@@ -155,7 +188,7 @@ class A1ClientFactoryTest {
     }
 
     private void whenGetGetControllerConfigReturn() throws ServiceException {
-        ControllerConfig controllerCfg = ImmutableControllerConfig.builder() //
+        ControllerConfig controllerCfg = ControllerConfig.builder() //
                 .name("name") //
                 .baseUrl("baseUrl") //
                 .password("pass") //
index eb00713..56dc7ed 100644 (file)
@@ -25,7 +25,6 @@ import java.util.Arrays;
 import java.util.Vector;
 
 import org.json.JSONObject;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
@@ -45,10 +44,9 @@ public class A1ClientHelper {
     }
 
     protected static Ric createRic(String url) {
-        RicConfig cfg = ImmutableRicConfig.builder().ricId("ric") //
+        RicConfig cfg = RicConfig.builder().ricId("ric") //
                 .baseUrl(url) //
                 .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
-                .controllerName("") //
                 .build();
         return new Ric(cfg);
     }
index f49020e..15e4983 100644 (file)
@@ -35,7 +35,6 @@ import java.net.URL;
 import java.nio.file.Files;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Optional;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -45,9 +44,7 @@ import org.mockito.stubbing.OngoingStubbing;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.CcsdkA1AdapterClient.AdapterOutput;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.CcsdkA1AdapterClient.AdapterRequest;
-import org.onap.ccsdk.oran.a1policymanagementservice.clients.ImmutableAdapterOutput.Builder;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableControllerConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
 import org.springframework.http.HttpStatus;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
@@ -74,7 +71,7 @@ class CcsdkA1AdapterClientTest {
     AsyncRestClient asyncRestClientMock;
 
     private ControllerConfig controllerConfig() {
-        return ImmutableControllerConfig.builder() //
+        return ControllerConfig.builder() //
                 .name("name") //
                 .baseUrl("baseUrl") //
                 .password(CONTROLLER_PASSWORD) //
@@ -113,9 +110,8 @@ class CcsdkA1AdapterClientTest {
         assertEquals(1, policyTypeIds.size());
         assertEquals(POLICY_TYPE_1_ID, policyTypeIds.get(0));
 
-        ImmutableAdapterRequest expectedParams = ImmutableAdapterRequest.builder() //
-                .nearRtRicUrl(expUrl) //
-                .build();
+        AdapterRequest expectedParams = new AdapterRequest(expUrl, null);
+
         String expInput = A1AdapterJsonHelper.createInputJsonString(expectedParams);
         verify(asyncRestClientMock).postWithAuthHeader(GET_A1_POLICY_URL, expInput, CONTROLLER_USERNAME,
                 CONTROLLER_PASSWORD);
@@ -160,9 +156,8 @@ class CcsdkA1AdapterClientTest {
         assertEquals(policyTypeId, respJson.getAsJsonObject().get("title").getAsString(),
                 "title should be updated to contain policyType ID");
 
-        ImmutableAdapterRequest expectedParams = ImmutableAdapterRequest.builder() //
-                .nearRtRicUrl(expUrl) //
-                .build();
+        AdapterRequest expectedParams = new AdapterRequest(expUrl, null);
+
         String expInput = A1AdapterJsonHelper.createInputJsonString(expectedParams);
 
         verify(asyncRestClientMock).postWithAuthHeader(GET_A1_POLICY_URL, expInput, CONTROLLER_USERNAME,
@@ -205,9 +200,8 @@ class CcsdkA1AdapterClientTest {
 
         assertEquals(1, returned.size());
         for (String expUrl : expUrls) {
-            ImmutableAdapterRequest expectedParams = ImmutableAdapterRequest.builder() //
-                    .nearRtRicUrl(expUrl) //
-                    .build();
+            AdapterRequest expectedParams = new AdapterRequest(expUrl, null);
+
             String expInput = A1AdapterJsonHelper.createInputJsonString(expectedParams);
             verify(asyncRestClientMock).postWithAuthHeader(GET_A1_POLICY_URL, expInput, CONTROLLER_USERNAME,
                     CONTROLLER_PASSWORD);
@@ -246,10 +240,7 @@ class CcsdkA1AdapterClientTest {
                 .block();
 
         assertEquals("OK", returned);
-        AdapterRequest expectedInputParams = ImmutableAdapterRequest.builder() //
-                .nearRtRicUrl(expUrl) //
-                .body(POLICY_JSON_VALID) //
-                .build();
+        AdapterRequest expectedInputParams = new AdapterRequest(expUrl, POLICY_JSON_VALID);
         String expInput = A1AdapterJsonHelper.createInputJsonString(expectedInputParams);
 
         verify(asyncRestClientMock).postWithAuthHeader(PUT_A1_URL, expInput, CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
@@ -282,10 +273,7 @@ class CcsdkA1AdapterClientTest {
                 controllerConfig(), asyncRestClientMock);
 
         final String policyJson = "{}";
-        AdapterOutput adapterOutput = ImmutableAdapterOutput.builder() //
-                .body("NOK") //
-                .httpStatus(HttpStatus.BAD_REQUEST.value()) // ERROR
-                .build();
+        AdapterOutput adapterOutput = new AdapterOutput(HttpStatus.BAD_REQUEST.value(), "NOK");
 
         String resp = A1AdapterJsonHelper.createOutputJsonString(adapterOutput);
         whenAsyncPostThenReturn(Mono.just(resp));
@@ -311,9 +299,8 @@ class CcsdkA1AdapterClientTest {
 
         clientUnderTest.deleteAllPolicies().blockLast();
 
-        ImmutableAdapterRequest expectedParams = ImmutableAdapterRequest.builder() //
-                .nearRtRicUrl(expUrl) //
-                .build();
+        AdapterRequest expectedParams = new AdapterRequest(expUrl, null);
+
         String expInput = A1AdapterJsonHelper.createInputJsonString(expectedParams);
         verify(asyncRestClientMock).postWithAuthHeader(DELETE_A1_URL, expInput, CONTROLLER_USERNAME,
                 CONTROLLER_PASSWORD);
@@ -363,9 +350,8 @@ class CcsdkA1AdapterClientTest {
         assertEquals("OK", response);
 
         String expUrl = RIC_1_URL + "/A1-P/v2/policytypes/type1/policies/policy1/status";
-        ImmutableAdapterRequest expectedParams = ImmutableAdapterRequest.builder() //
-                .nearRtRicUrl(expUrl) //
-                .build();
+        AdapterRequest expectedParams = new AdapterRequest(expUrl, null);
+
         String expInput = A1AdapterJsonHelper.createInputJsonString(expectedParams);
         verify(asyncRestClientMock).postWithAuthHeader(GET_A1_POLICY_STATUS_URL, expInput, CONTROLLER_USERNAME,
                 CONTROLLER_PASSWORD);
@@ -392,21 +378,14 @@ class CcsdkA1AdapterClientTest {
     }
 
     private String createOkResponseWithBody(Object body) {
-        AdapterOutput output = ImmutableAdapterOutput.builder() //
-                .body(gson().toJson(body)) //
-                .httpStatus(HttpStatus.OK.value()) //
-                .build();
+        AdapterOutput output = new AdapterOutput(HttpStatus.OK.value(), gson().toJson(body));
         return A1AdapterJsonHelper.createOutputJsonString(output);
     }
 
     private String createOkResponseString(boolean withBody) {
-        Builder responseBuilder = ImmutableAdapterOutput.builder().httpStatus(HttpStatus.OK.value());
-        if (withBody) {
-            responseBuilder.body(HttpStatus.OK.name());
-        } else {
-            responseBuilder.body(Optional.empty());
-        }
-        return A1AdapterJsonHelper.createOutputJsonString(responseBuilder.build());
+        String body = withBody ? HttpStatus.OK.name() : null;
+        AdapterOutput output = new AdapterOutput(HttpStatus.OK.value(), body);
+        return A1AdapterJsonHelper.createOutputJsonString(output);
     }
 
     private OngoingStubbing<Mono<String>> whenAsyncPostThenReturn(Mono<String> response) {
index 6aacc91..2ff07f1 100644 (file)
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -35,7 +34,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.junit.jupiter.MockitoExtension;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 
 import reactor.core.publisher.Flux;
@@ -66,11 +64,9 @@ class OscA1ClientTest {
 
     @BeforeEach
     void init() {
-        RicConfig ricConfig = ImmutableRicConfig.builder() //
+        RicConfig ricConfig = RicConfig.builder() //
                 .ricId("name") //
                 .baseUrl("RicBaseUrl") //
-                .managedElementIds(new ArrayList<>()) //
-                .controllerName("") //
                 .build();
         asyncRestClientMock = mock(AsyncRestClient.class);
         clientUnderTest = new OscA1Client(ricConfig, asyncRestClientMock);
index b470976..db4c79c 100644 (file)
@@ -80,7 +80,7 @@ class StdA1ClientTest {
 
     @Test
     void testGetPolicyIdentities() {
-        doReturn(RIC_URL).when(ricConfigMock).baseUrl();
+        doReturn(RIC_URL).when(ricConfigMock).getBaseUrl();
         Mono<String> policyIds = Mono.just(Arrays.asList(POLICY_1_ID, POLICY_2_ID).toString());
         when(asyncRestClientMock.get(anyString())).thenReturn(policyIds);
 
@@ -98,7 +98,7 @@ class StdA1ClientTest {
 
     @Test
     void testPutPolicyValidResponse() {
-        doReturn(RIC_URL).when(ricConfigMock).baseUrl();
+        doReturn(RIC_URL).when(ricConfigMock).getBaseUrl();
         when(asyncRestClientMock.put(anyString(), anyString())).thenReturn(Mono.just(POLICY_JSON));
 
         Mono<String> policyMono =
@@ -110,7 +110,7 @@ class StdA1ClientTest {
 
     @Test
     void testDeletePolicy() {
-        doReturn(RIC_URL).when(ricConfigMock).baseUrl();
+        doReturn(RIC_URL).when(ricConfigMock).getBaseUrl();
         final String url = policiesBaseUrl() + POLICY_1_ID;
         when(asyncRestClientMock.delete(url)).thenReturn(Mono.empty());
 
@@ -122,7 +122,7 @@ class StdA1ClientTest {
 
     @Test
     void testDeleteAllPolicies() {
-        doReturn(RIC_URL).when(ricConfigMock).baseUrl();
+        doReturn(RIC_URL).when(ricConfigMock).getBaseUrl();
         Mono<String> policyIds = Mono.just(Arrays.asList(POLICY_1_ID, POLICY_2_ID).toString());
         when(asyncRestClientMock.get(policiesUrl())).thenReturn(policyIds);
         when(asyncRestClientMock.delete(anyString())).thenReturn(Mono.empty());
index de55882..95c2042 100644 (file)
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -38,7 +37,6 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.junit.jupiter.MockitoExtension;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 
 import reactor.core.publisher.Flux;
@@ -69,11 +67,9 @@ class StdA1ClientV2Test {
 
     @BeforeEach
     void init() {
-        RicConfig ricConfig = ImmutableRicConfig.builder() //
+        RicConfig ricConfig = RicConfig.builder() //
                 .ricId("name") //
                 .baseUrl(RIC_URL) //
-                .managedElementIds(new ArrayList<>()) //
-                .controllerName("") //
                 .build();
         asyncRestClientMock = mock(AsyncRestClient.class);
         clientUnderTest = new StdA1ClientVersion2(ricConfig, asyncRestClientMock);
index 4a4e8a3..8e3e3a5 100644 (file)
@@ -59,25 +59,27 @@ class ApplicationConfigParserTest {
 
         ApplicationConfigParser.ConfigParserResult result = parserUnderTest.parse(jsonRootObject);
 
-        String topicUrl = result.dmaapProducerTopicUrl();
+        String topicUrl = result.getDmaapProducerTopicUrl();
         assertEquals("http://admin:admin@localhost:6845/events/A1-POLICY-AGENT-WRITE", topicUrl, "controller contents");
 
-        topicUrl = result.dmaapConsumerTopicUrl();
+        topicUrl = result.getDmaapConsumerTopicUrl();
         assertEquals(
                 "http://admin:admin@localhost:6845/events/A1-POLICY-AGENT-READ/users/policy-agent?timeout=15000&limit=100",
                 topicUrl, "controller contents");
 
-        Map<String, ControllerConfig> controllers = result.controllerConfigs();
+        Map<String, ControllerConfig> controllers = result.getControllerConfigs();
         assertEquals(1, controllers.size(), "size");
-        ImmutableControllerConfig expectedControllerConfig = ImmutableControllerConfig.builder() //
+        ControllerConfig expectedControllerConfig = ControllerConfig.builder() //
                 .baseUrl("http://localhost:8083/") //
                 .name("controller1") //
                 .userName("user") //
                 .password("password") //
                 .build(); //
-        assertEquals(expectedControllerConfig, controllers.get("controller1"), "controller contents");
 
-        assertEquals(2, result.ricConfigs().size());
+        ControllerConfig actual = controllers.get("controller1");
+        assertEquals(expectedControllerConfig, actual, "controller contents");
+
+        assertEquals(2, result.getRicConfigs().size());
     }
 
     private JsonObject getJsonRootObject() throws JsonIOException, JsonSyntaxException, IOException {
index 7a07542..abf91f2 100644 (file)
@@ -26,7 +26,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Vector;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -37,29 +36,23 @@ import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationCo
 @ExtendWith(MockitoExtension.class)
 class ApplicationConfigTest {
 
-    private static final ImmutableRicConfig RIC_CONFIG_1 = ImmutableRicConfig.builder() //
+    private static final RicConfig RIC_CONFIG_1 = RicConfig.builder() //
             .ricId("ric1") //
             .baseUrl("ric1_url") //
-            .managedElementIds(new Vector<>()) //
-            .controllerName("") //
             .build();
 
-    private static final ImmutableRicConfig RIC_CONFIG_2 = ImmutableRicConfig.builder() //
+    private static final RicConfig RIC_CONFIG_2 = RicConfig.builder() //
             .ricId("ric2") //
             .baseUrl("ric1_url") //
-            .managedElementIds(new Vector<>()) //
-            .controllerName("") //
             .build();
 
-    private static final ImmutableRicConfig RIC_CONFIG_3 = ImmutableRicConfig.builder() //
+    private static final RicConfig RIC_CONFIG_3 = RicConfig.builder() //
             .ricId("ric3") //
             .baseUrl("ric1_url") //
-            .managedElementIds(new Vector<>()) //
-            .controllerName("") //
             .build();
 
     ConfigParserResult configParserResult(RicConfig... rics) {
-        return ImmutableConfigParserResult.builder() //
+        return ConfigParserResult.builder() //
                 .ricConfigs(Arrays.asList(rics)) //
                 .dmaapConsumerTopicUrl("dmaapConsumerTopicUrl") //
                 .dmaapProducerTopicUrl("dmaapProducerTopicUrl") //
@@ -77,7 +70,7 @@ class ApplicationConfigTest {
         assertEquals(RicConfigUpdate.Type.ADDED, update.get(0).getType());
         assertTrue(appConfigUnderTest.getRicConfigs().contains(RIC_CONFIG_1), "Ric not added to configurations.");
 
-        assertEquals(RIC_CONFIG_1, appConfigUnderTest.getRic(RIC_CONFIG_1.ricId()),
+        assertEquals(RIC_CONFIG_1, appConfigUnderTest.getRic(RIC_CONFIG_1.getRicId()),
                 "Not correct Ric retrieved from configurations.");
 
         update = appConfigUnderTest.setConfiguration(configParserResult(RIC_CONFIG_1)).collectList().block();
@@ -98,11 +91,9 @@ class ApplicationConfigTest {
                 .setConfiguration(configParserResult(RIC_CONFIG_1, RIC_CONFIG_2, RIC_CONFIG_3)).collectList().block();
         assertEquals(3, update.size());
 
-        ImmutableRicConfig changedRicConfig = ImmutableRicConfig.builder() //
-                .ricId(RIC_CONFIG_1.ricId()) //
+        RicConfig changedRicConfig = RicConfig.builder() //
+                .ricId(RIC_CONFIG_1.getRicId()) //
                 .baseUrl("changed_ric1_url") //
-                .managedElementIds(new Vector<>()) //
-                .controllerName("") //
                 .build();
 
         update = appConfigUnderTest.setConfiguration(configParserResult(changedRicConfig, RIC_CONFIG_2, RIC_CONFIG_3))
@@ -110,7 +101,7 @@ class ApplicationConfigTest {
         assertEquals(1, update.size());
 
         assertEquals(RicConfigUpdate.Type.CHANGED, update.get(0).getType());
-        assertEquals(changedRicConfig, appConfigUnderTest.getRic(RIC_CONFIG_1.ricId()),
+        assertEquals(changedRicConfig, appConfigUnderTest.getRic(RIC_CONFIG_1.getRicId()),
                 "Changed Ric not retrieved from configurations.");
     }
 
index 569cb57..0484524 100644 (file)
@@ -46,15 +46,12 @@ import java.util.List;
 import org.json.JSONObject;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig.RicConfigUpdate;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableWebClientConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceCallbackInfo;
@@ -90,18 +87,16 @@ import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.TestPropertySource;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
 
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 import reactor.util.annotation.Nullable;
 
-@ExtendWith(SpringExtension.class)
 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
 @TestPropertySource(properties = { //
-        "server.ssl.key-store=./src/test/resources/keystore.jks", //
-        "app.webclient.trust-store=./src/test/resources/truststore.jks", //
+        "server.ssl.key-store=./config/keystore.jks", //
+        "app.webclient.trust-store=./config/truststore.jks", //
         "app.webclient.trust-store-used=true", //
         "app.vardata-directory=./target/testdata", //
         "app.filepath=" //
@@ -319,8 +314,10 @@ class ApplicationTest {
     @Test
     void testTrustValidation() {
         addRic("ric1");
+
         String rsp = restClient(true).get("/rics").block(); // restClient(true) enables trust validation
         assertThat(rsp).contains("ric1");
+
     }
 
     @Test
@@ -922,15 +919,20 @@ class ApplicationTest {
         final Instant startTime = Instant.now();
         List<Thread> threads = new ArrayList<>();
         List<ConcurrencyTestRunnable> tests = new ArrayList<>();
-        a1ClientFactory.setResponseDelay(Duration.ofMillis(1));
+        a1ClientFactory.setResponseDelay(Duration.ofMillis(2));
         addRic("ric");
         addPolicyType("type1", "ric");
         addPolicyType("type2", "ric");
 
+        final String NON_RESPONDING_RIC = "NonRespondingRic";
+        Ric nonRespondingRic = addRic(NON_RESPONDING_RIC);
+        MockA1Client a1Client = a1ClientFactory.getOrCreateA1Client(NON_RESPONDING_RIC);
+        a1Client.setErrorInject("errorInject");
+
         for (int i = 0; i < 10; ++i) {
             AsyncRestClient restClient = restClient();
-            ConcurrencyTestRunnable test =
-                    new ConcurrencyTestRunnable(restClient, supervision, a1ClientFactory, rics, policyTypes);
+            ConcurrencyTestRunnable test = new ConcurrencyTestRunnable(restClient, supervision, a1ClientFactory, rics,
+                    policyTypes);
             Thread thread = new Thread(test, "TestThread_" + i);
             thread.start();
             threads.add(thread);
@@ -944,19 +946,22 @@ class ApplicationTest {
         }
         assertThat(policies.size()).isZero();
         logger.info("Concurrency test took " + Duration.between(startTime, Instant.now()));
+
+        assertThat(nonRespondingRic.getState()).isEqualTo(RicState.UNAVAILABLE);
+        nonRespondingRic.setState(RicState.AVAILABLE);
     }
 
     private AsyncRestClient restClient(String baseUrl, boolean useTrustValidation) {
         WebClientConfig config = this.applicationConfig.getWebClientConfig();
-        config = ImmutableWebClientConfig.builder() //
-                .keyStoreType(config.keyStoreType()) //
-                .keyStorePassword(config.keyStorePassword()) //
-                .keyStore(config.keyStore()) //
-                .keyPassword(config.keyPassword()) //
+        config = WebClientConfig.builder() //
+                .keyStoreType(config.getKeyStoreType()) //
+                .keyStorePassword(config.getKeyStorePassword()) //
+                .keyStore(config.getKeyStore()) //
+                .keyPassword(config.getKeyPassword()) //
                 .isTrustStoreUsed(useTrustValidation) //
-                .trustStore(config.trustStore()) //
-                .trustStorePassword(config.trustStorePassword()) //
-                .httpProxyConfig(config.httpProxyConfig()) //
+                .trustStore(config.getTrustStore()) //
+                .trustStorePassword(config.getTrustStorePassword()) //
+                .httpProxyConfig(config.getHttpProxyConfig()) //
                 .build();
 
         AsyncRestClientFactory f = new AsyncRestClientFactory(config, new SecurityContext(""));
@@ -1041,11 +1046,10 @@ class ApplicationTest {
         if (managedElement != null) {
             mes.add(managedElement);
         }
-        return ImmutableRicConfig.builder() //
+        return RicConfig.builder() //
                 .ricId(ricId) //
                 .baseUrl(ricId) //
                 .managedElementIds(mes) //
-                .controllerName("") //
                 .build();
     }
 
index d500ba3..51a6838 100644 (file)
@@ -30,13 +30,11 @@ import java.time.Duration;
 import org.apache.commons.io.FileUtils;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.io.TempDir;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableWebClientConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
 import org.onap.ccsdk.oran.a1policymanagementservice.tasks.RefreshConfigTask;
@@ -52,13 +50,11 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.test.context.TestPropertySource;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
 
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 
-@ExtendWith(SpringExtension.class)
 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
 @TestPropertySource(properties = { //
         "server.ssl.key-store=./config/keystore.jks", //
@@ -166,15 +162,15 @@ class ConfigurationControllerTest {
 
     private AsyncRestClient restClient() {
         WebClientConfig config = this.applicationConfig.getWebClientConfig();
-        config = ImmutableWebClientConfig.builder() //
-                .keyStoreType(config.keyStoreType()) //
-                .keyStorePassword(config.keyStorePassword()) //
-                .keyStore(config.keyStore()) //
-                .keyPassword(config.keyPassword()) //
+        config = WebClientConfig.builder() //
+                .keyStoreType(config.getKeyStoreType()) //
+                .keyStorePassword(config.getKeyStorePassword()) //
+                .keyStore(config.getKeyStore()) //
+                .keyPassword(config.getKeyPassword()) //
                 .isTrustStoreUsed(false) //
-                .trustStore(config.trustStore()) //
-                .trustStorePassword(config.trustStorePassword()) //
-                .httpProxyConfig(config.httpProxyConfig()) //
+                .trustStore(config.getTrustStore()) //
+                .trustStorePassword(config.getTrustStorePassword()) //
+                .httpProxyConfig(config.getHttpProxyConfig()) //
                 .build();
 
         AsyncRestClientFactory f = new AsyncRestClientFactory(config, new SecurityContext(""));
index f09bd05..2ecb9c2 100644 (file)
@@ -38,7 +38,6 @@ import java.io.IOException;
 import java.net.URL;
 import java.time.Duration;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.Vector;
@@ -55,8 +54,6 @@ import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationCo
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfigParser;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfigParser.ConfigParserResult;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ConfigurationFile;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableConfigParserResult;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
@@ -77,11 +74,10 @@ class RefreshConfigTaskTest {
     ConfigurationFile configurationFileMock;
 
     private static final String RIC_1_NAME = "ric1";
-    private static final RicConfig CORRECT_RIC_CONIFG = ImmutableRicConfig.builder() //
+    private static final RicConfig CORRECT_RIC_CONIFG = RicConfig.builder() //
             .ricId(RIC_1_NAME) //
             .baseUrl("http://localhost:8080/") //
             .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
-            .controllerName("") //
             .build();
 
     private RefreshConfigTask createTestObject(boolean configFileExists) {
@@ -91,6 +87,7 @@ class RefreshConfigTaskTest {
     private RefreshConfigTask createTestObject(boolean configFileExists, Rics rics, Policies policies,
             boolean stubConfigFileExists) {
         SecurityContext secContext = new SecurityContext("");
+
         RefreshConfigTask obj =
                 spy(new RefreshConfigTask(configurationFileMock, appConfig, rics, policies, new Services(appConfig),
                         new PolicyTypes(appConfig), new A1ClientFactory(appConfig, secContext), secContext));
@@ -147,11 +144,8 @@ class RefreshConfigTaskTest {
     }
 
     ConfigParserResult configParserResult(RicConfig... rics) {
-        return ImmutableConfigParserResult.builder() //
+        return ConfigParserResult.builder() //
                 .ricConfigs(Arrays.asList(rics)) //
-                .dmaapConsumerTopicUrl("") //
-                .dmaapProducerTopicUrl("") //
-                .controllerConfigs(new HashMap<>()) //
                 .build();
     }
 
index b76131d..b2bf58e 100644 (file)
@@ -24,8 +24,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import java.time.Instant;
@@ -45,7 +45,7 @@ import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
@@ -65,7 +65,7 @@ class RicSupervisionTest {
             .schema("") //
             .build();
 
-    private static final Ric RIC_1 = new Ric(ImmutableRicConfig.builder() //
+    private static final Ric RIC_1 = new Ric(RicConfig.builder() //
             .ricId("ric_1") //
             .baseUrl("baseUrl1") //
             .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
@@ -148,7 +148,8 @@ class RicSupervisionTest {
         supervisorUnderTest.checkAllRics();
 
         verify(supervisorUnderTest).checkAllRics();
-        verifyNoMoreInteractions(supervisorUnderTest);
+        verify(synchronizationTaskMock, times(0)).synchronizeRic(RIC_1);
+        assertThat(RIC_1.getState()).isEqualTo(RicState.AVAILABLE);
     }
 
     @Test
@@ -156,18 +157,13 @@ class RicSupervisionTest {
         doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
         RIC_1.setState(RicState.UNAVAILABLE);
         rics.put(RIC_1);
-
         RicSupervision supervisorUnderTest = spy(createRicSupervision());
-
         doReturn(synchronizationTaskMock).when(supervisorUnderTest).createSynchronizationTask();
         doReturn(Mono.just(RIC_1)).when(synchronizationTaskMock).synchronizeRic(any());
-
         supervisorUnderTest.checkAllRics();
-
-        verify(supervisorUnderTest).checkAllRics();
-        verify(supervisorUnderTest).createSynchronizationTask();
         verify(synchronizationTaskMock).synchronizeRic(RIC_1);
-        verifyNoMoreInteractions(supervisorUnderTest);
+
+        assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
     }
 
     @Test
@@ -181,7 +177,8 @@ class RicSupervisionTest {
         supervisorUnderTest.checkAllRics();
 
         verify(supervisorUnderTest).checkAllRics();
-        verifyNoMoreInteractions(supervisorUnderTest);
+        verify(synchronizationTaskMock, times(0)).synchronizeRic(RIC_1);
+        assertThat(RIC_1.getState()).isEqualTo(RicState.SYNCHRONIZING);
     }
 
     @Test
@@ -197,7 +194,8 @@ class RicSupervisionTest {
         supervisorUnderTest.checkAllRics();
 
         verify(supervisorUnderTest).checkAllRics();
-        verifyNoMoreInteractions(supervisorUnderTest);
+        verify(synchronizationTaskMock, times(0)).synchronizeRic(RIC_1);
+
         assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
     }
 
@@ -219,9 +217,9 @@ class RicSupervisionTest {
         supervisorUnderTest.checkAllRics();
 
         verify(supervisorUnderTest).checkAllRics();
-        verify(supervisorUnderTest).createSynchronizationTask();
         verify(synchronizationTaskMock).synchronizeRic(RIC_1);
-        verifyNoMoreInteractions(supervisorUnderTest);
+
+        assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
     }
 
     @Test
@@ -242,9 +240,9 @@ class RicSupervisionTest {
         supervisorUnderTest.checkAllRics();
 
         verify(supervisorUnderTest).checkAllRics();
-        verify(supervisorUnderTest).createSynchronizationTask();
         verify(synchronizationTaskMock).synchronizeRic(RIC_1);
-        verifyNoMoreInteractions(supervisorUnderTest);
+
+        assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
     }
 
     @Test
@@ -261,7 +259,9 @@ class RicSupervisionTest {
         supervisorUnderTest.checkAllRics();
 
         verify(supervisorUnderTest).checkAllRics();
-        verifyNoMoreInteractions(supervisorUnderTest);
+        verify(synchronizationTaskMock, times(0)).synchronizeRic(RIC_1);
+
+        assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
     }
 
     @Test
@@ -283,9 +283,9 @@ class RicSupervisionTest {
         supervisorUnderTest.checkAllRics();
 
         verify(supervisorUnderTest).checkAllRics();
-        verify(supervisorUnderTest).createSynchronizationTask();
         verify(synchronizationTaskMock).synchronizeRic(RIC_1);
-        verifyNoMoreInteractions(supervisorUnderTest);
+
+        assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
     }
 
     @Test
@@ -311,9 +311,8 @@ class RicSupervisionTest {
         supervisorUnderTest.checkAllRics();
 
         verify(supervisorUnderTest).checkAllRics();
-        verify(supervisorUnderTest).createSynchronizationTask();
         verify(synchronizationTaskMock).synchronizeRic(RIC_1);
-        verifyNoMoreInteractions(supervisorUnderTest);
+        assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
     }
 
     @SuppressWarnings("unchecked")
index a5795ac..6386441 100644 (file)
@@ -46,7 +46,8 @@ import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
@@ -56,6 +57,8 @@ import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Service;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
+import org.springframework.web.reactive.function.client.WebClientRequestException;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
 
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
@@ -105,10 +108,9 @@ class RicSynchronizationTaskTest {
 
     @BeforeEach
     void init() {
-        ric1 = new Ric(ImmutableRicConfig.builder() //
+        ric1 = new Ric(RicConfig.builder() //
                 .ricId(RIC_1_NAME) //
                 .baseUrl("baseUrl1") //
-                .managedElementIds(Collections.emptyList()) //
                 .controllerName("controllerName") //
                 .build());
         policy1 = createPolicy("policyId1", false);
@@ -148,6 +150,35 @@ class RicSynchronizationTaskTest {
         assertThat(ric1.getSupportedPolicyTypeNames()).hasSize(1);
     }
 
+    @Test
+    void ricIdleAndErrorDeletingPoliciesAllTheTime_thenSynchronizationWithFailedRecovery() {
+        setUpCreationOfA1Client();
+        simulateRicWithNoPolicyTypes();
+        policies.put(policy1);
+        WebClientResponseException exception = new WebClientResponseException(404, "", null, null, null);
+        when(a1ClientMock.deleteAllPolicies()).thenReturn(Flux.error(exception));
+        RicSynchronizationTask synchronizerUnderTest = createTask();
+        ric1.setState(RicState.AVAILABLE);
+        synchronizerUnderTest.run(ric1);
+        await().untilAsserted(() -> RicState.UNAVAILABLE.equals(ric1.getState()));
+        assertThat(policies.size()).isZero();
+        assertThat(ric1.getState()).isEqualTo(RicState.UNAVAILABLE);
+    }
+
+    @Test
+    void testConnectionError() {
+        setUpCreationOfA1Client();
+        simulateRicWithNoPolicyTypes();
+        policies.put(policy1);
+        WebClientRequestException exception =
+                new WebClientRequestException(new ServiceException("x"), null, null, null);
+        when(a1ClientMock.deleteAllPolicies()).thenReturn(Flux.error(exception));
+        RicSynchronizationTask synchronizerUnderTest = createTask();
+        ric1.setState(RicState.AVAILABLE);
+        synchronizerUnderTest.run(ric1);
+        await().untilAsserted(() -> RicState.UNAVAILABLE.equals(ric1.getState()));
+    }
+
     @Test
     void ricIdlePolicyTypeInRepo_thenSynchronizationWithReuseOfTypeFromRepoAndCorrectServiceNotified() {
         rics.put(ric1);
@@ -234,58 +265,6 @@ class RicSynchronizationTaskTest {
         assertThat(ric1.getState()).isEqualTo(RicState.AVAILABLE);
     }
 
-    @Test
-    void ricIdleAndErrorDeletingPoliciesFirstTime_thenSynchronizationWithDeletionOfPolicies() {
-        ric1.setState(RicState.AVAILABLE);
-        rics.put(ric1);
-
-        policies.put(policy1);
-
-        setUpCreationOfA1Client();
-        simulateRicWithNoPolicyTypes();
-
-        when(a1ClientMock.deleteAllPolicies()) //
-                .thenReturn(Flux.error(new Exception("Exception"))) //
-                .thenReturn(Flux.just("OK"));
-
-        RicSynchronizationTask synchronizerUnderTest = createTask();
-
-        ric1.setState(RicState.UNAVAILABLE);
-        synchronizerUnderTest.run(ric1);
-        await().untilAsserted(() -> RicState.AVAILABLE.equals(ric1.getState()));
-
-        verify(a1ClientMock, times(2)).deleteAllPolicies();
-        verifyNoMoreInteractions(a1ClientMock);
-
-        assertThat(policyTypes.size()).isZero();
-        assertThat(policies.size()).isZero();
-        assertThat(ric1.getState()).isEqualTo(RicState.AVAILABLE);
-    }
-
-    @Test
-    void ricIdleAndErrorDeletingPoliciesAllTheTime_thenSynchronizationWithFailedRecovery() {
-        setUpCreationOfA1Client();
-        simulateRicWithNoPolicyTypes();
-
-        policies.put(policy1);
-
-        String originalErrorMessage = "Exception";
-        when(a1ClientMock.deleteAllPolicies()).thenReturn(Flux.error(new Exception(originalErrorMessage)));
-
-        RicSynchronizationTask synchronizerUnderTest = createTask();
-
-        ric1.setState(RicState.AVAILABLE);
-        synchronizerUnderTest.run(ric1);
-        await().untilAsserted(() -> RicState.UNAVAILABLE.equals(ric1.getState()));
-
-        verify(a1ClientMock, times(2)).deleteAllPolicies();
-        verifyNoMoreInteractions(a1ClientMock);
-
-        assertThat(policyTypes.size()).isZero();
-        assertThat(policies.size()).isZero();
-        assertThat(ric1.getState()).isEqualTo(RicState.UNAVAILABLE);
-    }
-
     private void setUpCreationOfA1Client() {
         when(a1ClientFactoryMock.createA1Client(any(Ric.class))).thenReturn(Mono.just(a1ClientMock));
         doReturn(Flux.empty()).when(a1ClientMock).deleteAllPolicies();
index 294b220..c8c7c72 100644 (file)
@@ -34,7 +34,6 @@ import ch.qos.logback.core.read.ListAppender;
 
 import java.time.Duration;
 import java.time.Instant;
-import java.util.Collections;
 
 import org.awaitility.Durations;
 import org.junit.jupiter.api.Test;
@@ -44,7 +43,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
@@ -70,11 +68,9 @@ class ServiceSupervisionTest {
     private Services services;
     private Service service;
     private Policies policies;
-    private RicConfig ricConfig = ImmutableRicConfig.builder() //
+    private RicConfig ricConfig = RicConfig.builder() //
             .ricId(RIC_NAME) //
             .baseUrl("baseUrl") //
-            .managedElementIds(Collections.emptyList()) //
-            .controllerName("") //
             .build();
     private Ric ric = new Ric(ricConfig);
     private PolicyType policyType = PolicyType.builder() //
index 2a3b28e..b76f1e7 100644 (file)
@@ -28,6 +28,8 @@ import java.time.Duration;
 import java.util.List;
 import java.util.Vector;
 
+import lombok.Setter;
+
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
@@ -44,7 +46,12 @@ import reactor.core.publisher.MonoSink;
 public class MockA1Client implements A1Client {
     Policies policies;
     private final PolicyTypes policyTypes;
-    private final Duration asynchDelay;
+
+    @Setter
+    private Duration asynchDelay;
+
+    @Setter
+    private String errorInject;
 
     public MockA1Client(String ricId, ApplicationConfig appConfig, PolicyTypes policyTypes, Duration asynchDelay) {
         this.policyTypes = policyTypes;
@@ -117,14 +124,19 @@ public class MockA1Client implements A1Client {
     }
 
     private <T> Mono<T> mono(T value) {
-        if (this.asynchDelay.isZero()) {
-            return Mono.just(value);
-        } else {
-            return Mono.create(monoSink -> asynchResponse(monoSink, value));
+        Mono<T> res = Mono.just(value);
+        if (!this.asynchDelay.isZero()) {
+            res = Mono.create(monoSink -> asynchResponse(monoSink, value));
         }
+
+        if (this.errorInject != null) {
+            res = res.flatMap(x -> monoError(this.errorInject, HttpStatus.BAD_GATEWAY));
+        }
+
+        return res;
     }
 
-    public static Mono<String> monoError(String responseBody, HttpStatus status) {
+    public static <T> Mono<T> monoError(String responseBody, HttpStatus status) {
         byte[] responseBodyBytes = responseBody.getBytes(StandardCharsets.UTF_8);
         WebClientResponseException a1Exception = new WebClientResponseException(status.value(),
                 status.getReasonPhrase(), null, responseBodyBytes, StandardCharsets.UTF_8, null);
diff --git a/a1-policy-management/src/test/resources/keystore.jks b/a1-policy-management/src/test/resources/keystore.jks
deleted file mode 100644 (file)
index 675785b..0000000
Binary files a/a1-policy-management/src/test/resources/keystore.jks and /dev/null differ
index 959f53f..fef2382 100644 (file)
@@ -1,4 +1,4 @@
-{  
+{
    "config": {
       "description": "Application configuration",
       "ric": [
@@ -13,6 +13,7 @@
          {
             "name": "ric2",
             "baseUrl": "http://localhost:8081/",
+            "customAdapterClass": "org.onap.ccsdk.oran.a1policymanagementservice.clients.StdA1ClientVersion2$Factory",
             "managedElementIds": [
                "kista_3",
                "kista_4"
index b00720c..6e1de75 100644 (file)
@@ -1,6 +1,6 @@
 {
    "config": {
-      "//description" : "Test",
+      "description": "Test",
       "controller": [
          {
             "name": "controller1",
@@ -14,6 +14,7 @@
             "name": "ric1",
             "controller": "controller1",
             "baseUrl": "http://localhost:8083/",
+            "customAdapterClass": "org.onap.ccsdk.oran.a1policymanagementservice.clients.StdA1ClientVersion2$Factory",
             "managedElementIds": [
                "kista_1",
                "kista_2"
@@ -53,4 +54,4 @@
          }
       }
    }
-}
+}
\ No newline at end of file
diff --git a/a1-policy-management/src/test/resources/truststore.jks b/a1-policy-management/src/test/resources/truststore.jks
deleted file mode 100644 (file)
index e883cd6..0000000
Binary files a/a1-policy-management/src/test/resources/truststore.jks and /dev/null differ
index 9fc8e7b..5c5915c 100644 (file)
@@ -79,7 +79,7 @@
                 },
                 "keep_alive_interval_seconds": {
                     "format": "int64",
-                    "description": "keep alive interval for the service. This is a heartbeat supervision of the service, which in regular intervals must invoke a 'keepalive' REST call. When a service does not invoke this call within the given time, it is considered unavailable. An unavailable service will be automatically deregistered and its policies will be deleted. Value 0 means no timeout supervision.",
+                    "description": "keep alive interval for the service. This is used to enable optional heartbeat supervision of the service. If set (> 0) the registered service should regularly invoke a 'keepalive' REST call. When a service fails to invoke this 'keepalive' call within the configured time, the service is considered unavailable. An unavailable service will be automatically deregistered and its policies will be deleted. Value 0 means timeout supervision is disabled.",
                     "type": "integer"
                 }
             }
         },
         "/a1-policy/v2/services/{service_id}/keepalive": {"put": {
             "summary": "Heartbeat indicates that the service is running",
-            "description": "A registered service must call this in regular intervals to indicate that it is in operation. Absence of this call will lead to that the service will be deregistered and all its policies are removed.",
+            "description": "A registered service should invoke this operation regularly to indicate that it is still alive. If a registered service fails to invoke this operation before the end of a timeout period the service will be deregistered and all its A1 policies wil be removed. (This timeout can be set or disabled when each service is initially registered)",
             "operationId": "keepAliveService",
             "responses": {
                 "200": {
             "url": "http://www.apache.org/licenses/LICENSE-2.0"
         },
         "description": "<h2>General<\/h2><p>The O-RAN Non-RT RIC Policy Management Service provides a REST API for management of A1 policies. <br/>The main tasks of the service are:<\/p><ul><li>A1 Policy creation, modification and deletion.<\/li><li>Monitoring and maintaining consistency of the SMO view of A1 policies and the Near-RT RICs<\/li><li>Maintaining a view of supported Near-RT RIC policy types<\/li><li>Supervision of using services (R-APPs). When a service is unavailable, its policies are removed.<\/li><\/ul><h2>APIs provided by the service<\/h2><h3>A1 Policy Management<\/h3><p>This is an API for management of A1 Policies.<\/p><ul><li>A1 Policy retrieval, creation, modification and deletion.<\/li><li>Retrieval of supported A1 Policy types for a Near-RT RIC<\/li><li>Retrieval of status for existing A1 policies<\/li><\/ul><h3>Management of configuration<\/h3><p>API for updating and retrieval of the component configuration. Note that there other ways to maintain the configuration.<\/p><h3>Callbacks<\/h3><p>These are endpoints that are invoked by this service. The callbacks are registered in this service at service registration.<\/p><h3>NearRT-RIC Repository<\/h3><p>This is an API that provides support for looking up a NearRT-RIC. Each A1 policy is targeted for one Near-RT RIC.<\/p><h3>Health Check<\/h3><p>API used for supervision of the PMS component.<\/p><h3>Service Registry and Supervision<\/h3><p>API used for registering services that uses PMS. Each A1 policy is owned by a service. PMS can supervise each registered service and will automatically remove policies for unavailable services.<\/p>",
-        "title": "A1 Policy management service",
+        "title": "A1 Policy Management Service",
         "version": "1.1.0"
     },
     "tags": [
index 3fd496b..1f84399 100644 (file)
@@ -1,6 +1,6 @@
 openapi: 3.0.1
 info:
-  title: A1 Policy management service
+  title: A1 Policy Management Service
   description: <h2>General</h2><p>The O-RAN Non-RT RIC Policy Management Service provides
     a REST API for management of A1 policies. <br/>The main tasks of the service are:</p><ul><li>A1
     Policy creation, modification and deletion.</li><li>Monitoring and maintaining
@@ -434,9 +434,11 @@ paths:
       tags:
       - Service Registry and Supervision
       summary: Heartbeat indicates that the service is running
-      description: A registered service must call this in regular intervals to indicate
-        that it is in operation. Absence of this call will lead to that the service
-        will be deregistered and all its policies are removed.
+      description: A registered service should invoke this operation regularly to
+        indicate that it is still alive. If a registered service fails to invoke this
+        operation before the end of a timeout period the service will be deregistered
+        and all its A1 policies wil be removed. (This timeout can be set or disabled
+        when each service is initially registered)
       operationId: keepAliveService
       parameters:
       - name: service_id
@@ -896,12 +898,13 @@ components:
           description: identity of the service
         keep_alive_interval_seconds:
           type: integer
-          description: keep alive interval for the service. This is a heartbeat supervision
-            of the service, which in regular intervals must invoke a 'keepalive' REST
-            call. When a service does not invoke this call within the given time,
-            it is considered unavailable. An unavailable service will be automatically
-            deregistered and its policies will be deleted. Value 0 means no timeout
-            supervision.
+          description: keep alive interval for the service. This is used to enable
+            optional heartbeat supervision of the service. If set (> 0) the registered
+            service should regularly invoke a 'keepalive' REST call. When a service
+            fails to invoke this 'keepalive' call within the configured time, the
+            service is considered unavailable. An unavailable service will be automatically
+            deregistered and its policies will be deleted. Value 0 means timeout supervision
+            is disabled.
           format: int64
       description: Information for one service
     policy_info_list_v2: