REST Style alignment for A1 Policy Management 16/111316/7
authorPatrikBuhr <patrik.buhr@est.tech>
Tue, 11 Aug 2020 07:24:25 +0000 (09:24 +0200)
committerPatrikBuhr <patrik.buhr@est.tech>
Thu, 20 Aug 2020 07:21:40 +0000 (09:21 +0200)
Created a structure for support of different NBI APIs.
A version 2 is started, which introduces changes initiated by
reviews and aligns to https://opensource.zalando.com/restful-api-guidelines/#118

More alignment will be done in later commits.

Issue-ID: CCSDK-2498
Change-Id: I810ecce79b5e2462cc77a1c2e7c638fbc6d54774
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
66 files changed:
a1-policy-management/api/api_generated.yaml [new file with mode: 0644]
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/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/OscA1Client.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOnapA1Client.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1Client.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/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/RicConfig.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/VoidResponse.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/Consts.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/PolicyController.java [moved from a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/PolicyController.java with 85% similarity]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/PolicyInfo.java [moved from a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/PolicyInfo.java with 94% similarity]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/RicInfo.java [moved from a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/RicInfo.java with 94% similarity]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/RicRepositoryController.java [moved from a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/RicRepositoryController.java with 88% similarity]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java [moved from a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceController.java with 96% similarity]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceRegistrationInfo.java [moved from a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceRegistrationInfo.java with 91% similarity]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceStatus.java [moved from a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceStatus.java with 97% similarity]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/StatusController.java [moved from a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/StatusController.java with 98% similarity]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/Consts.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ErrorResponse.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/JsonObject.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/JsonSchema.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyIdList.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfoList.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicySchemaList.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeIdList.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfo.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfoList.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicRepositoryController.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceController.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceRegistrationInfo.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceStatus.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceStatusList.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/StatusController.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Policies.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Policy.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/PolicyType.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/PolicyTypes.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/repository/Rics.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/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/ServiceSupervision.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTestV1.java [moved from a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTest.java with 96% similarity]
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTestV2.java [new file with mode: 0644]
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ConcurrencyTestRunnable.java
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/OscA1ClientTest.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/dmaap/DmaapMessageHandlerTest.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/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1ClientFactory.java

diff --git a/a1-policy-management/api/api_generated.yaml b/a1-policy-management/api/api_generated.yaml
new file mode 100644 (file)
index 0000000..06bbf33
--- /dev/null
@@ -0,0 +1,1341 @@
+swagger: '2.0'
+info:
+  description: |
+    The O-RAN NonRT-RIC PolicyAgent provides a REST API for management of policices. 
+    It provides support for: 
+    -Supervision of clients (R-APPs) to eliminate stray policies in case of failure 
+    -Consistency monitoring of the SMO view of policies and the actual situation in the NearRT-RICs 
+    -Consistency monitoring of NearRT-RIC capabilities (policy types)-Policy configuration. 
+    This includes:-One REST API towards all NearRT-RICs in the network 
+    -Query functions that can find all policies in a NearRT-RIC, all policies owned by a service (R-APP), 
+    all policies of a type etc. 
+    -Maps O1 resources (ManagedElement) as defined in O1 to the controlling NearRT-RIC of A1 policices.
+  version: 1.1.0
+  title: A1 Policy management service
+  contact:
+    name: Ericsson Software Technology
+    email: nonrtric@est.tech
+host: 'localhost:8081'
+basePath: /
+tags:
+  - name: A1 Policy Management Version 1.0
+    description: Policy Controller
+  - name: A1 Policy Management Version 2.0 (in progress)
+    description: Policy Controller
+paths:
+  /policies:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Query policies
+      operationId: getPoliciesUsingGET_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: ric
+          in: query
+          description: The name of the NearRT-RIC to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: service
+          in: query
+          description: The name of the service to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: type
+          in: query
+          description: The name of the policy type to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policies
+          schema:
+            type: array
+            items:
+              $ref: '#/definitions/policy_info_v1'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC or type not found
+          schema:
+            type: string
+      deprecated: false
+  /policy:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Returns a policy configuration
+      operationId: getPolicyUsingGET_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: id
+          in: query
+          description: The identity of the policy instance.
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy found
+          schema:
+            type: object
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Policy is not found
+      deprecated: false
+    put:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Put a policy
+      operationId: putPolicyUsingPUT_1
+      consumes:
+        - application/json
+      produces:
+        - '*/*'
+      parameters:
+        - name: id
+          in: query
+          description: The identity of the policy instance.
+          required: true
+          type: string
+          allowEmptyValue: false
+        - in: body
+          name: jsonBody
+          description: jsonBody
+          required: true
+          schema:
+            type: object
+        - name: ric
+          in: query
+          description: The name of the NearRT-RIC where the policy will be created.
+          required: true
+          type: string
+          allowEmptyValue: false
+        - name: service
+          in: query
+          description: The name of the service creating the policy.
+          required: true
+          type: string
+          allowEmptyValue: false
+        - name: transient
+          in: query
+          description: If the policy is transient or not (boolean defaulted to false). A policy is transient if it will be forgotten when the service needs to reconnect to the NearRT-RIC.
+          required: false
+          type: boolean
+          default: false
+          allowEmptyValue: false
+          x-example: false
+        - name: type
+          in: query
+          description: The name of the policy type.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy updated
+        '201':
+          description: Policy created
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC or policy type is not found
+          schema:
+            type: string
+        '423':
+          description: NearRT-RIC is not operational
+          schema:
+            type: string
+      deprecated: false
+    delete:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Delete a policy
+      operationId: deletePolicyUsingDELETE_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: id
+          in: query
+          description: The identity of the policy instance.
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Not used
+        '204':
+          description: Policy deleted
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Policy is not found
+          schema:
+            type: string
+        '423':
+          description: NearRT-RIC is not operational
+          schema:
+            type: string
+      deprecated: false
+  /policy_ids:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: 'Query policies, only IDs returned'
+      operationId: getPolicyIdsUsingGET_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: ric
+          in: query
+          description: The name of the NearRT-RIC to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: service
+          in: query
+          description: The name of the service to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: type
+          in: query
+          description: The name of the policy type to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy ids
+          schema:
+            type: array
+            items:
+              type: string
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC or type not found
+          schema:
+            type: string
+      deprecated: false
+  /policy_schema:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Returns one policy type schema definition
+      operationId: getPolicySchemaUsingGET
+      produces:
+        - '*/*'
+      parameters:
+        - name: id
+          in: query
+          description: The identity of the policy type to get the definition for.
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy schema
+          schema:
+            type: object
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: The policy type is not found
+          schema:
+            type: string
+      deprecated: false
+  /policy_schemas:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Returns policy type schema definitions
+      operationId: getPolicySchemasUsingGET_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: ric
+          in: query
+          description: The name of the NearRT-RIC to get the definitions for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy schemas
+          schema:
+            type: array
+            items:
+              type: object
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC is not found
+          schema:
+            type: string
+      deprecated: false
+  /policy_status:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Returns a policy status
+      operationId: getPolicyStatusUsingGET_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: id
+          in: query
+          description: The identity of the policy.
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy status
+          schema:
+            type: object
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Policy is not found
+          schema:
+            type: string
+      deprecated: false
+  /policy_types:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Query policy type names
+      operationId: getPolicyTypesUsingGET_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: ric
+          in: query
+          description: The name of the NearRT-RIC to get types for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy type names
+          schema:
+            type: array
+            items:
+              type: string
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC is not found
+          schema:
+            type: string
+      deprecated: false
+  /ric:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Returns the name of a RIC managing one Mananged Element
+      operationId: getRicUsingGET
+      produces:
+        - '*/*'
+      parameters:
+        - name: managedElementId
+          in: query
+          description: The identity of the Managed Element
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: NearRT-RIC is found
+          schema:
+            type: string
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC is not found
+          schema:
+            type: string
+      deprecated: false
+  /rics:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Query NearRT-RIC information
+      operationId: getRicsUsingGET
+      produces:
+        - '*/*'
+      parameters:
+        - name: policyType
+          in: query
+          description: The name of the policy type
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: OK
+          schema:
+            type: array
+            items:
+              $ref: '#/definitions/ric_info_v1'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Policy type is not found
+          schema:
+            type: string
+      deprecated: false
+  /service:
+    put:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Register a service
+      operationId: putServiceUsingPUT_1
+      consumes:
+        - application/json
+      produces:
+        - '*/*'
+      parameters:
+        - in: body
+          name: registrationInfo
+          description: registrationInfo
+          required: true
+          schema:
+            $ref: '#/definitions/service_registration_info_v1'
+      responses:
+        '200':
+          description: Service updated
+          schema:
+            type: string
+        '201':
+          description: Service created
+          schema:
+            type: string
+        '400':
+          description: The ServiceRegistrationInfo is not accepted
+          schema:
+            type: string
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Not Found
+      deprecated: false
+  /services:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Returns service information
+      operationId: getServicesUsingGET_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: name
+          in: query
+          description: The name of the service
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: OK
+          schema:
+            type: array
+            items:
+              $ref: '#/definitions/service_status_v1'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Service is not found
+          schema:
+            type: string
+      deprecated: false
+    delete:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Delete a service
+      operationId: deleteServiceUsingDELETE_1
+      produces:
+        - '*/*'
+      parameters:
+        - name: name
+          in: query
+          description: The name of the service
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: OK
+          schema:
+            type: string
+        '204':
+          description: Service deleted
+          schema:
+            type: string
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Service not found
+          schema:
+            type: string
+      deprecated: false
+  /services/keepalive:
+    put:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Heartbeat from a serice
+      operationId: keepAliveServiceUsingPUT_1
+      consumes:
+        - application/json
+      produces:
+        - '*/*'
+      parameters:
+        - name: name
+          in: query
+          description: The name of the service
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: 'Service supervision timer refreshed, OK'
+          schema:
+            type: string
+        '201':
+          description: Created
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: 'The service is not found, needs re-registration'
+      deprecated: false
+  /status:
+    get:
+      tags:
+        - A1 Policy Management Version 1.0
+      summary: Returns status and statistics of this service
+      operationId: getStatusUsingGET_1
+      produces:
+        - '*/*'
+      responses:
+        '200':
+          description: Service is living
+          schema:
+            type: string
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Not Found
+      deprecated: false
+  /v2/policies:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Query policies
+      description: 'If several query parameters are defined, the policies matching all conditions are returned'
+      operationId: getPoliciesUsingGET
+      produces:
+        - application/json
+      parameters:
+        - name: policytype_id
+          in: query
+          description: The identity of the policy type to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: ric_id
+          in: query
+          description: The identity of the NearRT-RIC to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: service_id
+          in: query
+          description: The identity of the service to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policies
+          schema:
+            $ref: '#/definitions/policy_info_list_v2'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: 'NearRT-RIC, policy type or service not found'
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/policy:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Returns a policy configuration
+      operationId: getPolicyUsingGET
+      produces:
+        - application/json
+      parameters:
+        - name: policy_id
+          in: query
+          description: The identity of the policy instance.
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy found
+          schema:
+            $ref: '#/definitions/json_object'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Policy is not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+    put:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Create or update a policy
+      operationId: putPolicyUsingPUT
+      consumes:
+        - application/json
+      produces:
+        - application/json
+      parameters:
+        - in: body
+          name: jsonBody
+          description: jsonBody
+          required: true
+          schema:
+            type: object
+        - name: policy_id
+          in: query
+          description: The identity of the policy instance.
+          required: true
+          type: string
+          allowEmptyValue: false
+        - name: policytype_id
+          in: query
+          description: The identity of the policy type.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: ric_id
+          in: query
+          description: The identity of the NearRT-RIC where the policy will be created.
+          required: true
+          type: string
+          allowEmptyValue: false
+        - name: service_id
+          in: query
+          description: The identity of the service creating the policy.
+          required: true
+          type: string
+          allowEmptyValue: false
+        - name: transient
+          in: query
+          description: If the policy is transient or not (boolean defaulted to false). A policy is transient if it will not be recreated in the NearRT-RIC when it has been lost (for instance due to a restart)
+          required: false
+          type: boolean
+          default: false
+          allowEmptyValue: false
+          x-example: false
+      responses:
+        '200':
+          description: Policy updated
+        '201':
+          description: Policy created
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC or policy type is not found
+          schema:
+            $ref: '#/definitions/error_information'
+        '423':
+          description: NearRT-RIC is not operational
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+    delete:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Delete a policy
+      operationId: deletePolicyUsingDELETE
+      produces:
+        - '*/*'
+      parameters:
+        - name: policy_id
+          in: query
+          description: The identity of the policy instance.
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Not used
+        '204':
+          description: Policy deleted
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Policy is not found
+          schema:
+            $ref: '#/definitions/error_information'
+        '423':
+          description: NearRT-RIC is not operational
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/policy-ids:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: 'Query policies, only IDs returned'
+      operationId: getPolicyIdsUsingGET
+      produces:
+        - application/json
+      parameters:
+        - name: policytype_id
+          in: query
+          description: The identity of the policy type to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: ric_id
+          in: query
+          description: The identity of the NearRT-RIC to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: service_id
+          in: query
+          description: The identity of the service to get policies for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy ids
+          schema:
+            $ref: '#/definitions/policy_id_list_v2'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC or type not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/policy-schemas:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Returns policy type schema definitions
+      operationId: getPolicySchemasUsingGET
+      produces:
+        - application/json
+      parameters:
+        - name: policytype_id
+          in: query
+          description: 'The identity of the policy type to get the definition for. When this parameter is given, max one schema will be returned'
+          required: true
+          type: string
+          allowEmptyValue: false
+        - name: ric_id
+          in: query
+          description: The identity of the NearRT-RIC to get the definitions for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy schemas
+          schema:
+            $ref: '#/definitions/policy_schema_list_v2'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC is not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/policy-status:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Returns a policy status
+      operationId: getPolicyStatusUsingGET
+      produces:
+        - application/json
+      parameters:
+        - name: policy_id
+          in: query
+          description: The identity of the policy.
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy status
+          schema:
+            $ref: '#/definitions/json_object'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Policy is not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/policy-types:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Query policy type identities
+      operationId: getPolicyTypesUsingGET
+      produces:
+        - application/json
+      parameters:
+        - name: ric_id
+          in: query
+          description: The identity of the NearRT-RIC to get types for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Policy type IDs
+          schema:
+            $ref: '#/definitions/policy_type_id_list_v2'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC is not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/ric:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Returns info for the NearRT-RIC with the given identity or managing one Mananged Element
+      operationId: getRicUsingGET_1
+      produces:
+        - application/json
+      parameters:
+        - name: managed_element_id
+          in: query
+          description: 'The identity of a Managed Element. If given, the NearRT-RIC managing the ME is returned.'
+          required: false
+          type: string
+          allowEmptyValue: false
+        - name: ric_id
+          in: query
+          description: The identity of a NearRT-RIC to get information for.
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: NearRT-RIC is found
+          schema:
+            $ref: '#/definitions/ric_info_v2'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: NearRT-RIC is not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/rics:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Query NearRT-RIC information
+      operationId: getRicsUsingGET_1
+      produces:
+        - application/json
+      parameters:
+        - name: policytype_id
+          in: query
+          description: 'The identity of a policy type. If given, all NearRT-RICs supporteing the policy type are returned'
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/ric_info_list_v2'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Policy type is not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/services:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Returns service information
+      operationId: getServicesUsingGET
+      produces:
+        - application/json
+      parameters:
+        - name: service_id
+          in: query
+          description: The identity of the service
+          required: false
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: OK
+          schema:
+            $ref: '#/definitions/service_list_v2'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Service is not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+    put:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Register a service
+      operationId: putServiceUsingPUT
+      consumes:
+        - application/json
+      produces:
+        - '*/*'
+      parameters:
+        - in: body
+          name: registrationInfo
+          description: registrationInfo
+          required: true
+          schema:
+            $ref: '#/definitions/service_registration_info_v2'
+      responses:
+        '200':
+          description: Service updated
+          schema:
+            type: object
+        '201':
+          description: Service created
+          schema:
+            type: object
+        '400':
+          description: The ServiceRegistrationInfo is not accepted
+          schema:
+            $ref: '#/definitions/error_information'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Not Found
+      deprecated: false
+    delete:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Delete a service
+      operationId: deleteServiceUsingDELETE
+      produces:
+        - '*/*'
+      parameters:
+        - name: service_id
+          in: query
+          description: The name of the service
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: Not used
+        '204':
+          description: Service deleted
+          schema:
+            type: object
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Service not found
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/services/keepalive:
+    put:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Heartbeat indicates that the service is running
+      operationId: keepAliveServiceUsingPUT
+      consumes:
+        - application/json
+      produces:
+        - '*/*'
+      parameters:
+        - name: service_id
+          in: query
+          description: The identity of the service
+          required: true
+          type: string
+          allowEmptyValue: false
+      responses:
+        '200':
+          description: 'Service supervision timer refreshed, OK'
+          schema:
+            type: object
+        '201':
+          description: Created
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: 'The service is not found, needs re-registration'
+          schema:
+            $ref: '#/definitions/error_information'
+      deprecated: false
+  /v2/status:
+    get:
+      tags:
+        - A1 Policy Management Version 2.0 (in progress)
+      summary: Returns status and statistics of this service
+      operationId: getStatusUsingGET
+      produces:
+        - application/json
+      responses:
+        '200':
+          description: Service is living
+          schema:
+            $ref: '#/definitions/status_info_v2'
+        '401':
+          description: Unauthorized
+        '403':
+          description: Forbidden
+        '404':
+          description: Not Found
+      deprecated: false
+definitions:
+  Mono«ResponseEntity«object»»:
+    type: object
+    title: Mono«ResponseEntity«object»»
+  Mono«ResponseEntity«string»»:
+    type: object
+    title: Mono«ResponseEntity«string»»
+  error_information:
+    type: object
+    properties:
+      detail:
+        type: string
+        example: Policy type not found
+        description: ' A human-readable explanation specific to this occurrence of the problem.'
+      status:
+        type: integer
+        format: int32
+        example: 503
+        description: 'The HTTP status code generated by the origin server for this occurrence of the problem. '
+    title: error_information
+    description: 'Problem as defined in https://tools.ietf.org/html/rfc7807'
+  json_object:
+    type: object
+    title: json_object
+    description: A JSON object. The schema is defined by the Policy Type
+  policy_id_list_v2:
+    type: object
+    properties:
+      policy_ids:
+        type: array
+        description: Policy identities
+        items:
+          type: string
+    title: policy_id_list_v2
+    description: A list of policy identities
+  policy_info_list_v2:
+    type: object
+    properties:
+      policies:
+        type: array
+        description: List of policy information
+        items:
+          $ref: '#/definitions/policy_info_v2'
+    title: policy_info_list_v2
+    description: List of policy information
+  policy_info_v1:
+    type: object
+    properties:
+      id:
+        type: string
+        description: identity of the policy
+      json:
+        type: object
+        description: the configuration of the policy
+      lastModified:
+        type: string
+        description: 'timestamp, last modification time'
+      ric:
+        type: string
+        description: identity of the target NearRT-RIC
+      service:
+        type: string
+        description: the name of the service owning the policy
+      type:
+        type: string
+        description: name of the policy type
+    title: policy_info_v1
+  policy_info_v2:
+    type: object
+    properties:
+      last_modified:
+        type: string
+        description: 'timestamp, last modification time'
+      policy_data:
+        type: object
+        description: the configuration of the policy
+      policy_id:
+        type: string
+        description: identity of the policy
+      policy_type_id:
+        type: string
+        description: name of the policy type
+      ric_id:
+        type: string
+        description: identity of the target NearRT-RIC
+      service_id:
+        type: string
+        description: the name of the service owning the policy
+    title: policy_info_v2
+    description: Information for one A1-P Policy
+  policy_schema_list_v2:
+    type: object
+    properties:
+      policy_schemas:
+        type: array
+        description: Policy type json schemas
+        items:
+          type: object
+    title: policy_schema_list_v2
+    description: Policy type json schemas
+  policy_type_id_list_v2:
+    type: object
+    properties:
+      policy_type_ids:
+        type: array
+        description: Policy type identities
+        items:
+          type: string
+    title: policy_type_id_list_v2
+    description: Information about policy types
+  ric_info_list_v2:
+    type: object
+    properties:
+      rics:
+        type: array
+        description: List of NearRT-RIC information
+        items:
+          $ref: '#/definitions/ric_info_v2'
+    title: ric_info_list_v2
+    description: List of NearRT-RIC information
+  ric_info_v1:
+    type: object
+    properties:
+      managedElementIds:
+        type: array
+        description: O1 identities for managed entities
+        items:
+          type: string
+      policyTypes:
+        type: array
+        description: supported policy types
+        items:
+          type: string
+      ricName:
+        type: string
+        description: identity of the NearRT-RIC
+      state:
+        type: string
+        description: state info
+    title: ric_info_v1
+  ric_info_v2:
+    type: object
+    properties:
+      managed_element_ids:
+        type: array
+        description: O1 identities for managed entities
+        items:
+          type: string
+      policy_type_ids:
+        type: array
+        description: supported policy types
+        items:
+          type: string
+      ric_id:
+        type: string
+        description: identity of the NearRT-RIC
+      state:
+        type: string
+        description: |-
+          State for the NearRT-RIC, values: 
+          UNAVAILABLE: The NearRT-RIC is not avialable, information may be inconsistent 
+          AVAILABLE: The normal state. Policies can be configured. +
+          SYNCHRONIZING: The Policy Management Service is synchronizing the view of the NearRT-RIC. Policies cannot be configured. 
+          CONSISTENCY_CHECK: A consistency check between the Policy Management Service and the NearRT-RIC. Policies cannot be configured.
+        enum:
+          - UNAVAILABLE
+          - AVAILABLE
+          - SYNCHRONIZING
+          - CONSISTENCY_CHECK
+    title: ric_info_v2
+    description: Information for a NearRT-RIC
+  service_list_v2:
+    type: object
+    properties:
+      service_list:
+        type: array
+        description: List of service information
+        items:
+          $ref: '#/definitions/service_status_v2'
+    title: service_list_v2
+    description: List of service information
+  service_registration_info_v1:
+    type: object
+    properties:
+      callbackUrl:
+        type: string
+        description: callback for notifying of RIC synchronization
+      keepAliveIntervalSeconds:
+        type: integer
+        format: int64
+        description: 'keep alive interval for the service. This is a heartbeat supervision of the service, which in regular intevals must invoke a ''keepAlive'' REST call. When a service does not invoke this call within the given time, it is considered unavailble. An unavailable service will be automatically deregistered and its policies will be deleted. Value 0 means no timeout supervision.'
+      serviceName:
+        type: string
+    title: service_registration_info_v1
+  service_registration_info_v2:
+    type: object
+    required:
+      - service_id
+    properties:
+      callback_url:
+        type: string
+        description: callback for notifying of RIC synchronization
+      keep_alive_interval_seconds:
+        type: integer
+        format: int64
+        description: 'keep alive interval for the service. This is a heartbeat supervision of the service, which in regular intevals must invoke a ''keepAlive'' REST call. When a service does not invoke this call within the given time, it is considered unavailble. An unavailable service will be automatically deregistered and its policies will be deleted. Value 0 means no timeout supervision.'
+      service_id:
+        type: string
+        description: identity of the service
+    title: service_registration_info_v2
+    description: Information for one service
+  service_status_v1:
+    type: object
+    properties:
+      callbackUrl:
+        type: string
+        description: callback for notifying of RIC synchronization
+      keepAliveIntervalSeconds:
+        type: integer
+        format: int64
+        description: policy keep alive timeout
+      serviceName:
+        type: string
+        description: identity of the service
+      timeSinceLastActivitySeconds:
+        type: integer
+        format: int64
+        description: time since last invocation by the service
+    title: service_status_v1
+  service_status_v2:
+    type: object
+    properties:
+      callback_url:
+        type: string
+        description: callback for notifying of RIC synchronization
+      keep_alive_interval_seconds:
+        type: integer
+        format: int64
+        description: policy keep alive timeout
+      service_id:
+        type: string
+        description: identity of the service
+      time_since_last_activity_seconds:
+        type: integer
+        format: int64
+        description: time since last invocation by the service
+    title: service_status_v2
+  status_info_v2:
+    type: object
+    properties:
+      status:
+        type: string
+        description: status text
+    title: status_info_v2
+  void:
+    type: object
+    title: void
+    description: Void/empty
+
index 7e25ba1..4b68428 100644 (file)
@@ -31,14 +31,16 @@ import springfox.documentation.builders.ApiInfoBuilder;
 import springfox.documentation.builders.PathSelectors;
 import springfox.documentation.builders.RequestHandlerSelectors;
 import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
 import springfox.documentation.spi.DocumentationType;
 import springfox.documentation.spring.web.plugins.Docket;
 import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
 /**
  * Swagger configuration class that uses swagger2 documentation type and scans
- * all the controllers under org.onap.ccsdk.oran.a1policymanagementservice.controllers package. To
- * access the swagger gui go to http://ip:port/swagger-ui.html
+ * all the controllers under
+ * org.onap.ccsdk.oran.a1policymanagementservice.controllers package. To access
+ * the swagger gui go to http://ip:port/swagger-ui.html
  *
  */
 @Configuration
@@ -46,8 +48,17 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
 public class SwaggerConfig extends WebMvcConfigurationSupport {
 
     static final String API_TITLE = "A1 Policy management service";
-    static final String DESCRIPTION = "This page lists all the rest apis for the service.";
-    static final String VERSION = "1.0";
+    static final String DESCRIPTION =
+        "The O-RAN NonRT-RIC PolicyAgent provides a REST API for management of policices. \n"
+            + "It provides support for: \n"
+            + "-Supervision of clients (R-APPs) to eliminate stray policies in case of failure \n"
+            + "-Consistency monitoring of the SMO view of policies and the actual situation in the NearRT-RICs \n"
+            + "-Consistency monitoring of NearRT-RIC capabilities (policy types)" + "-Policy configuration. \n"
+            + "This includes:" + "-One REST API towards all NearRT-RICs in the network \n"
+            + "-Query functions that can find all policies in a NearRT-RIC, all policies owned by a service (R-APP), \n"
+            + "all policies of a type etc. \n"
+            + "-Maps O1 resources (ManagedElement) as defined in O1 to the controlling NearRT-RIC of A1 policices.\n";
+    static final String VERSION = "1.1.0";
     @SuppressWarnings("squid:S1075") // Refactor your code to get this URI from a customizable parameter.
     static final String RESOURCES_PATH = "classpath:/META-INF/resources/";
     static final String WEBJARS_PATH = RESOURCES_PATH + "webjars/";
@@ -57,7 +68,7 @@ public class SwaggerConfig extends WebMvcConfigurationSupport {
     /**
      * Gets the API info.
      *
-     * @return the API info.
+     * @return the API info.This page lists all the rest apis for the service.
      */
     @Bean
     public Docket api() {
@@ -78,9 +89,14 @@ public class SwaggerConfig extends WebMvcConfigurationSupport {
             .title(API_TITLE) //
             .description(DESCRIPTION) //
             .version(VERSION) //
+            .contact(contact()) //
             .build();
     }
 
+    private static Contact contact() {
+        return new Contact("Ericsson Software Technology", "", "nonrtric@est.tech");
+    }
+
     @Override
     protected void addResourceHandlers(ResourceHandlerRegistry registry) {
         registry.addResourceHandler(SWAGGER_UI) //
index f8f79e5..2b49357 100644 (file)
@@ -60,9 +60,9 @@ public class A1ClientFactory {
      * means that after the first successful creation it won't have to try which
      * protocol to use, but can create the client directly.
      *
-     * @param ric The RIC to get a client for.
+     * @param ric The NearRT-RIC to get a client for.
      * @return a client with the correct protocol, or a ServiceException if none of
-     *         the protocols are supported by the Ric.
+     *         the protocols are supported by the NearRT-RIC.
      */
     public Mono<A1Client> createA1Client(Ric ric) {
         return getProtocolVersion(ric) //
@@ -91,7 +91,7 @@ public class A1ClientFactory {
         String controllerName = ric.getConfig().controllerName();
         if (controllerName.isEmpty()) {
             ric.setProtocolVersion(A1ProtocolType.UNKNOWN);
-            throw new ServiceException("No controller configured for RIC: " + ric.name());
+            throw new ServiceException("No controller configured for NearRT-RIC: " + ric.id());
         }
         try {
             return this.appConfig.getControllerConfig(controllerName);
@@ -105,7 +105,7 @@ public class A1ClientFactory {
         if (!ric.getConfig().controllerName().isEmpty()) {
             ric.setProtocolVersion(A1ProtocolType.UNKNOWN);
             throw new ServiceException(
-                "Controller config should be empty, ric: " + ric.name() + " when using protocol version: " + version);
+                "Controller config should be empty, ric: " + ric.id() + " when using protocol version: " + version);
         }
     }
 
@@ -124,10 +124,11 @@ public class A1ClientFactory {
                 .onErrorResume(notUsed -> fetchVersion(ric, A1ProtocolType.SDNC_OSC_STD_V1_1)) //
                 .onErrorResume(notUsed -> fetchVersion(ric, A1ProtocolType.SDNC_ONAP)) //
                 .doOnNext(ric::setProtocolVersion)
-                .doOnNext(version -> logger.debug("Established protocol version:{} for Ric: {}", version, ric.name())) //
-                .doOnError(notUsed -> logger.warn("Could not get protocol version from RIC: {}", ric.name())) //
+                .doOnNext(
+                    version -> logger.debug("Established protocol version:{} for NearRT-RIC: {}", version, ric.id())) //
+                .doOnError(notUsed -> logger.warn("Could not get protocol version from NearRT-RIC: {}", ric.id())) //
                 .onErrorResume(
-                    notUsed -> Mono.error(new ServiceException("Protocol negotiation failed for " + ric.name())));
+                    notUsed -> Mono.error(new ServiceException("Protocol negotiation failed for " + ric.id())));
         } else {
             return Mono.just(ric.getProtocolVersion());
         }
index 55532e6..c3de6b2 100644 (file)
@@ -185,10 +185,14 @@ public class AsyncRestClient {
         final Class<String> clazz = String.class;
         return request.retrieve() //
             .toEntity(clazz) //
-            .doOnNext(entity -> logger.trace("{} Received: {}", traceTag, entity.getBody())) //
+            .doOnNext(entity -> logReceivedData(traceTag, entity)) //
             .doOnError(throwable -> onHttpError(traceTag, throwable));
     }
 
+    private void logReceivedData(Object traceTag, ResponseEntity<String> entity) {
+        logger.trace("{} Received: {} {}", traceTag, entity.getBody(), entity.getHeaders().getContentType());
+    }
+
     private static Object createTraceTag() {
         return sequenceNumber.incrementAndGet();
     }
index 4f26b86..bdbb916 100644 (file)
@@ -123,7 +123,7 @@ public class OscA1Client implements A1Client {
 
     public OscA1Client(RicConfig ricConfig, AsyncRestClient restClient) {
         this.restClient = restClient;
-        logger.debug("OscA1Client for ric: {}", ricConfig.name());
+        logger.debug("OscA1Client for ric: {}", ricConfig.ricId());
 
         uri = new UriBuilder(ricConfig);
     }
@@ -163,13 +163,13 @@ public class OscA1Client implements A1Client {
 
     @Override
     public Mono<String> putPolicy(Policy policy) {
-        String policyUri = this.uri.createPutPolicyUri(policy.type().name(), policy.id());
+        String policyUri = this.uri.createPutPolicyUri(policy.type().id(), policy.id());
         return restClient.put(policyUri, policy.json());
     }
 
     @Override
     public Mono<String> deletePolicy(Policy policy) {
-        return deletePolicyById(policy.type().name(), policy.id());
+        return deletePolicyById(policy.type().id(), policy.id());
     }
 
     @Override
@@ -186,7 +186,7 @@ public class OscA1Client implements A1Client {
 
     @Override
     public Mono<String> getPolicyStatus(Policy policy) {
-        String statusUri = uri.createGetPolicyStatusUri(policy.type().name(), policy.id());
+        String statusUri = uri.createGetPolicyStatusUri(policy.type().id(), policy.id());
         return restClient.get(statusUri);
 
     }
index 90e6149..0591e66 100644 (file)
@@ -67,7 +67,7 @@ public class SdncOnapA1Client implements A1Client {
     public SdncOnapA1Client(RicConfig ricConfig, ControllerConfig controllerConfig, WebClientConfig clientConfig) {
         this(ricConfig, controllerConfig,
             new AsyncRestClient(controllerConfig.baseUrl() + "/restconf/operations", clientConfig));
-        logger.debug("SdncOnapA1Client for ric: {}, a1ControllerBaseUrl: {}", ricConfig.name(),
+        logger.debug("SdncOnapA1Client for ric: {}, a1ControllerBaseUrl: {}", ricConfig.ricId(),
             controllerConfig.baseUrl());
     }
 
@@ -110,7 +110,7 @@ public class SdncOnapA1Client implements A1Client {
     public Mono<String> putPolicy(Policy policy) {
         SdncOnapAdapterInput inputParams = ImmutableSdncOnapAdapterInput.builder() //
             .nearRtRicId(ricConfig.baseUrl()) //
-            .policyTypeId(policy.type().name()) //
+            .policyTypeId(policy.type().id()) //
             .policyInstanceId(policy.id()) //
             .policyInstance(policy.json()) //
             .properties(new ArrayList<>()) //
@@ -125,7 +125,7 @@ public class SdncOnapA1Client implements A1Client {
 
     @Override
     public Mono<String> deletePolicy(Policy policy) {
-        return deletePolicyByTypeId(policy.type().name(), policy.id());
+        return deletePolicyByTypeId(policy.type().id(), policy.id());
     }
 
     @Override
index c9e613c..dffb9dd 100644 (file)
@@ -81,9 +81,10 @@ public class SdncOscA1Client implements A1Client {
     /**
      * Constructor that creates the REST client to use.
      *
-     * @param protocolType the southbound protocol of the controller. Supported protocols are SDNC_OSC_STD_V1_1 and
-     *        SDNC_OSC_OSC_V1
-     * @param ricConfig the configuration of the Ric to communicate with
+     * @param protocolType the southbound protocol of the controller. Supported
+     *        protocols are SDNC_OSC_STD_V1_1 and SDNC_OSC_OSC_V1
+     * @param ricConfig the configuration of the NearRT-RIC to communicate
+     *        with
      * @param controllerConfig the configuration of the SDNC controller to use
      *
      * @throws IllegalArgumentException when the protocolType is wrong.
@@ -92,15 +93,16 @@ public class SdncOscA1Client implements A1Client {
         WebClientConfig clientConfig) {
         this(protocolType, ricConfig, controllerConfig,
             new AsyncRestClient(controllerConfig.baseUrl() + "/restconf/operations", clientConfig));
-        logger.debug("SdncOscA1Client for ric: {}, a1Controller: {}", ricConfig.name(), controllerConfig);
+        logger.debug("SdncOscA1Client for ric: {}, a1Controller: {}", ricConfig.ricId(), controllerConfig);
     }
 
     /**
      * Constructor where the REST client to use is provided.
      *
-     * @param protocolType the southbound protocol of the controller. Supported protocols are SDNC_OSC_STD_V1_1 and
-     *        SDNC_OSC_OSC_V1
-     * @param ricConfig the configuration of the Ric to communicate with
+     * @param protocolType the southbound protocol of the controller. Supported
+     *        protocols are SDNC_OSC_STD_V1_1 and SDNC_OSC_OSC_V1
+     * @param ricConfig the configuration of the NearRT-RIC to communicate
+     *        with
      * @param controllerConfig the configuration of the SDNC controller to use
      * @param restClient the REST client to use
      *
@@ -155,14 +157,14 @@ public class SdncOscA1Client implements A1Client {
     public Mono<String> putPolicy(Policy policy) {
         return getUriBuilder() //
             .flatMap(builder -> {
-                String ricUrl = builder.createPutPolicyUri(policy.type().name(), policy.id());
+                String ricUrl = builder.createPutPolicyUri(policy.type().id(), policy.id());
                 return post("putA1Policy", ricUrl, Optional.of(policy.json()));
             });
     }
 
     @Override
     public Mono<String> deletePolicy(Policy policy) {
-        return deletePolicyById(policy.type().name(), policy.id());
+        return deletePolicyById(policy.type().id(), policy.id());
     }
 
     @Override
@@ -198,7 +200,7 @@ public class SdncOscA1Client implements A1Client {
     public Mono<String> getPolicyStatus(Policy policy) {
         return getUriBuilder() //
             .flatMap(builder -> {
-                String ricUrl = builder.createGetPolicyStatusUri(policy.type().name(), policy.id());
+                String ricUrl = builder.createGetPolicyStatusUri(policy.type().id(), policy.id());
                 return post("getA1PolicyStatus", ricUrl, Optional.empty());
             });
     }
index 0f76353..51beea7 100644 (file)
@@ -102,7 +102,7 @@ public class StdA1ClientVersion1 implements A1Client {
 
     @Override
     public Mono<String> putPolicy(Policy policy) {
-        return restClient.put(uri.createPutPolicyUri(policy.type().name(), policy.id()), policy.json());
+        return restClient.put(uri.createPutPolicyUri(policy.type().id(), policy.id()), policy.json());
     }
 
     @Override
@@ -134,7 +134,7 @@ public class StdA1ClientVersion1 implements A1Client {
 
     @Override
     public Mono<String> getPolicyStatus(Policy policy) {
-        return restClient.get(uri.createGetPolicyStatusUri(policy.type().name(), policy.id()));
+        return restClient.get(uri.createGetPolicyStatusUri(policy.type().id(), policy.id()));
     }
 
     private Flux<String> getPolicyIds() {
index f03a0ff..4f8e87f 100644 (file)
@@ -98,10 +98,10 @@ public class ApplicationConfig {
         return controllerConfig;
     }
 
-    public synchronized RicConfig getRic(String ricName) throws ServiceException {
-        RicConfig ricConfig = this.ricConfigs.get(ricName);
+    public synchronized RicConfig getRic(String ricId) throws ServiceException {
+        RicConfig ricConfig = this.ricConfigs.get(ricId);
         if (ricConfig == null) {
-            throw new ServiceException("Could not find ric configuration: " + ricName);
+            throw new ServiceException("Could not find ric configuration: " + ricId);
         }
         return ricConfig;
     }
@@ -133,16 +133,16 @@ public class ApplicationConfig {
 
         Map<String, RicConfig> newRicConfigs = new HashMap<>();
         for (RicConfig newConfig : parserResult.ricConfigs()) {
-            RicConfig oldConfig = this.ricConfigs.get(newConfig.name());
-            this.ricConfigs.remove(newConfig.name());
+            RicConfig oldConfig = this.ricConfigs.get(newConfig.ricId());
+            this.ricConfigs.remove(newConfig.ricId());
             if (oldConfig == null) {
-                newRicConfigs.put(newConfig.name(), newConfig);
+                newRicConfigs.put(newConfig.ricId(), 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.name(), newConfig);
+                newRicConfigs.put(newConfig.ricId(), newConfig);
             } else {
-                newRicConfigs.put(oldConfig.name(), oldConfig);
+                newRicConfigs.put(oldConfig.ricId(), oldConfig);
             }
         }
         for (RicConfig deletedConfig : this.ricConfigs.values()) {
index f3fbb2f..07c04e1 100644 (file)
@@ -25,6 +25,7 @@ import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -101,8 +102,8 @@ public class ApplicationConfigParser {
             if (!ricUrls.add(ric.baseUrl())) {
                 throw new ServiceException("Configuration error, more than one RIC URL: " + ric.baseUrl());
             }
-            if (!ricNames.add(ric.name())) {
-                throw new ServiceException("Configuration error, more than one RIC with name: " + ric.name());
+            if (!ricNames.add(ric.ricId())) {
+                throw new ServiceException("Configuration error, more than one RIC with name: " + ric.ricId());
             }
             if (!ric.controllerName().isEmpty() && controllerConfigs.get(ric.controllerName()) == null) {
                 throw new ServiceException(
@@ -117,8 +118,8 @@ public class ApplicationConfigParser {
         for (JsonElement ricElem : getAsJsonArray(config, "ric")) {
             JsonObject ricAsJson = ricElem.getAsJsonObject();
             JsonElement controllerNameElement = ricAsJson.get(CONTROLLER);
-            ImmutableRicConfig ricConfig = ImmutableRicConfig.builder() //
-                .name(get(ricAsJson, "name").getAsString()) //
+            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() : "") //
@@ -160,12 +161,14 @@ public class ApplicationConfigParser {
         return managedElementIds;
     }
 
-    private static JsonElement get(JsonObject obj, String memberName) throws ServiceException {
-        JsonElement elem = obj.get(memberName);
-        if (elem == null) {
-            throw new ServiceException("Could not find member: '" + memberName + "' in: " + obj);
+    private static JsonElement get(JsonObject obj, String... alternativeMemberNames) throws ServiceException {
+        for (String memberName : alternativeMemberNames) {
+            JsonElement elem = obj.get(memberName);
+            if (elem != null) {
+                return elem;
+            }
         }
-        return elem;
+        throw new ServiceException("Could not find member: " + Arrays.toString(alternativeMemberNames) + " in: " + obj);
     }
 
     private JsonArray getAsJsonArray(JsonObject obj, String memberName) throws ServiceException {
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/VoidResponse.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/VoidResponse.java
new file mode 100644 (file)
index 0000000..6ee656c
--- /dev/null
@@ -0,0 +1,32 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+
+import io.swagger.annotations.ApiModel;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "void", description = "Void/empty")
+public class VoidResponse {
+    private VoidResponse() {
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/Consts.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/Consts.java
new file mode 100644 (file)
index 0000000..cef31c3
--- /dev/null
@@ -0,0 +1,29 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
+
+public class Consts {
+
+    public static final String V1_API_NAME = "A1 Policy Management Version 1.0";
+
+    private Consts() {
+    }
+}
@@ -18,7 +18,7 @@
  * ========================LICENSE_END===================================
  */
 
-package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -30,6 +30,7 @@ import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 import java.lang.invoke.MethodHandles;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -37,6 +38,7 @@ import java.util.List;
 import lombok.Getter;
 
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.VoidResponse;
 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType;
@@ -63,7 +65,7 @@ import org.springframework.web.reactive.function.client.WebClientResponseExcepti
 import reactor.core.publisher.Mono;
 
 @RestController
-@Api(tags = "A1 Policy Management")
+@Api(tags = Consts.V1_API_NAME)
 public class PolicyController {
 
     public static class RejectionException extends Exception {
@@ -98,9 +100,9 @@ public class PolicyController {
     @ApiResponses(
         value = {
             @ApiResponse(code = 200, message = "Policy schemas", response = Object.class, responseContainer = "List"), //
-            @ApiResponse(code = 404, message = "RIC is not found", response = String.class)})
+            @ApiResponse(code = 404, message = "NearRT-RIC is not found", response = String.class)})
     public ResponseEntity<String> getPolicySchemas( //
-        @ApiParam(name = "ric", required = false, value = "The name of the Near-RT RIC to get the definitions for.") //
+        @ApiParam(name = "ric", required = false, value = "The name of the NearRT-RIC to get the definitions for.") //
         @RequestParam(name = "ric", required = false) String ricName) {
         if (ricName == null) {
             Collection<PolicyType> types = this.policyTypes.getAll();
@@ -120,9 +122,9 @@ public class PolicyController {
     @ApiResponses(
         value = { //
             @ApiResponse(code = 200, message = "Policy schema", response = Object.class),
-            @ApiResponse(code = 404, message = "RIC is not found", response = String.class)})
+            @ApiResponse(code = 404, message = "The policy type is not found", response = String.class)})
     public ResponseEntity<String> getPolicySchema( //
-        @ApiParam(name = "id", required = true, value = "The ID of the policy type to get the definition for.") //
+        @ApiParam(name = "id", required = true, value = "The identity of the policy type to get the definition for.") //
         @RequestParam(name = "id", required = true) String id) {
         try {
             PolicyType type = policyTypes.getType(id);
@@ -141,9 +143,9 @@ public class PolicyController {
                 message = "Policy type names",
                 response = String.class,
                 responseContainer = "List"),
-            @ApiResponse(code = 404, message = "RIC is not found", response = String.class)})
+            @ApiResponse(code = 404, message = "NearRT-RIC is not found", response = String.class)})
     public ResponseEntity<String> getPolicyTypes( //
-        @ApiParam(name = "ric", required = false, value = "The name of the Near-RT RIC to get types for.") //
+        @ApiParam(name = "ric", required = false, value = "The name of the NearRT-RIC to get types for.") //
         @RequestParam(name = "ric", required = false) String ricName) {
         if (ricName == null) {
             Collection<PolicyType> types = this.policyTypes.getAll();
@@ -166,7 +168,7 @@ public class PolicyController {
             @ApiResponse(code = 404, message = "Policy is not found")} //
     )
     public ResponseEntity<String> getPolicy( //
-        @ApiParam(name = "id", required = true, value = "The ID of the policy instance.") //
+        @ApiParam(name = "id", required = true, value = "The identity of the policy instance.") //
         @RequestParam(name = "id", required = true) String id) {
         try {
             Policy p = policies.getPolicy(id);
@@ -180,15 +182,16 @@ public class PolicyController {
     @ApiOperation(value = "Delete a policy", response = Object.class)
     @ApiResponses(
         value = { //
-            @ApiResponse(code = 204, message = "Policy deleted", response = Object.class),
+            @ApiResponse(code = 200, message = "Not used", response = VoidResponse.class),
+            @ApiResponse(code = 204, message = "Policy deleted", response = VoidResponse.class),
             @ApiResponse(code = 404, message = "Policy is not found", response = String.class),
-            @ApiResponse(code = 423, message = "RIC is not operational", response = String.class)})
+            @ApiResponse(code = 423, message = "NearRT-RIC is not operational", response = String.class)})
     public Mono<ResponseEntity<Object>> deletePolicy( //
-        @ApiParam(name = "id", required = true, value = "The ID of the policy instance.") //
+        @ApiParam(name = "id", required = true, value = "The identity of the policy instance.") //
         @RequestParam(name = "id", required = true) String id) {
         try {
             Policy policy = policies.getPolicy(id);
-            keepServiceAlive(policy.ownerServiceName());
+            keepServiceAlive(policy.ownerServiceId());
             Ric ric = policy.ric();
             return ric.getLock().lock(LockType.SHARED) //
                 .flatMap(notUsed -> assertRicStateIdle(ric)) //
@@ -208,24 +211,24 @@ public class PolicyController {
     @ApiOperation(value = "Put a policy", response = String.class)
     @ApiResponses(
         value = { //
-            @ApiResponse(code = 201, message = "Policy created", response = Object.class), //
-            @ApiResponse(code = 200, message = "Policy updated", response = Object.class), //
-            @ApiResponse(code = 423, message = "RIC is not operational", response = String.class), //
-            @ApiResponse(code = 404, message = "RIC or policy type is not found", response = String.class) //
+            @ApiResponse(code = 201, message = "Policy created", response = VoidResponse.class), //
+            @ApiResponse(code = 200, message = "Policy updated", response = VoidResponse.class), //
+            @ApiResponse(code = 423, message = "NearRT-RIC is not operational", response = String.class), //
+            @ApiResponse(code = 404, message = "NearRT-RIC or policy type is not found", response = String.class) //
         })
     public Mono<ResponseEntity<Object>> putPolicy( //
         @ApiParam(name = "type", required = false, value = "The name of the policy type.") //
         @RequestParam(name = "type", required = false, defaultValue = "") String typeName, //
-        @ApiParam(name = "id", required = true, value = "The ID of the policy instance.") //
+        @ApiParam(name = "id", required = true, value = "The identity of the policy instance.") //
         @RequestParam(name = "id", required = true) String instanceId, //
-        @ApiParam(name = "ric", required = true, value = "The name of the Near-RT RIC where the policy will be " + //
+        @ApiParam(name = "ric", required = true, value = "The name of the NearRT-RIC where the policy will be " + //
             "created.") //
         @RequestParam(name = "ric", required = true) String ricName, //
         @ApiParam(name = "service", required = true, value = "The name of the service creating the policy.") //
         @RequestParam(name = "service", required = true) String service, //
         @ApiParam(name = "transient", required = false, value = "If the policy is transient or not (boolean " + //
             "defaulted to false). A policy is transient if it will be forgotten when the service needs to " + //
-            "reconnect to the Near-RT RIC.") //
+            "reconnect to the NearRT-RIC.") //
         @RequestParam(name = "transient", required = false, defaultValue = "false") boolean isTransient, //
         @RequestBody Object jsonBody) {
 
@@ -241,8 +244,8 @@ public class PolicyController {
             .json(jsonString) //
             .type(type) //
             .ric(ric) //
-            .ownerServiceName(service) //
-            .lastModified(getTimeStampUtc()) //
+            .ownerServiceId(service) //
+            .lastModified(Instant.now()) //
             .isTransient(isTransient) //
             .build();
 
@@ -282,10 +285,10 @@ public class PolicyController {
     private Mono<Object> validateModifiedPolicy(Policy policy) {
         // Check that ric is not updated
         Policy current = this.policies.get(policy.id());
-        if (current != null && !current.ric().name().equals(policy.ric().name())) {
+        if (current != null && !current.ric().id().equals(policy.ric().id())) {
             RejectionException e = new RejectionException("Policy cannot change RIC, policyId: " + current.id() + //
-                ", RIC name: " + current.ric().name() + //
-                ", new name: " + policy.ric().name(), HttpStatus.CONFLICT);
+                ", RIC name: " + current.ric().id() + //
+                ", new name: " + policy.ric().id(), HttpStatus.CONFLICT);
             logger.debug("Request rejected, {}", e.getMessage());
             return Mono.error(e);
         }
@@ -293,10 +296,10 @@ public class PolicyController {
     }
 
     private Mono<Object> checkSupportedType(Ric ric, PolicyType type) {
-        if (!ric.isSupportingType(type.name())) {
+        if (!ric.isSupportingType(type.id())) {
             logger.debug("Request rejected, type not supported, RIC: {}", ric);
-            RejectionException e = new RejectionException(
-                "Type: " + type.name() + " not supported by RIC: " + ric.name(), HttpStatus.NOT_FOUND);
+            RejectionException e = new RejectionException("Type: " + type.id() + " not supported by RIC: " + ric.id(),
+                HttpStatus.NOT_FOUND);
             return Mono.error(e);
         }
         return Mono.just("OK");
@@ -308,7 +311,7 @@ public class PolicyController {
         } else {
             logger.debug("Request rejected RIC not IDLE, ric: {}", ric);
             RejectionException e = new RejectionException(
-                "Ric is not operational, RIC name: " + ric.name() + ", state: " + ric.getState(), HttpStatus.LOCKED);
+                "Ric is not operational, RIC name: " + ric.id() + ", state: " + ric.getState(), HttpStatus.LOCKED);
             return Mono.error(e);
         }
     }
@@ -318,11 +321,11 @@ public class PolicyController {
     @ApiResponses(
         value = {
             @ApiResponse(code = 200, message = "Policies", response = PolicyInfo.class, responseContainer = "List"),
-            @ApiResponse(code = 404, message = "RIC or type not found", response = String.class)})
+            @ApiResponse(code = 404, message = "NearRT-RIC or type not found", response = String.class)})
     public ResponseEntity<String> getPolicies( //
         @ApiParam(name = "type", required = false, value = "The name of the policy type to get policies for.") //
         @RequestParam(name = "type", required = false) String type, //
-        @ApiParam(name = "ric", required = false, value = "The name of the Near-RT RIC to get policies for.") //
+        @ApiParam(name = "ric", required = false, value = "The name of the NearRT-RIC to get policies for.") //
         @RequestParam(name = "ric", required = false) String ric, //
         @ApiParam(name = "service", required = false, value = "The name of the service to get policies for.") //
         @RequestParam(name = "service", required = false) String service) //
@@ -331,7 +334,7 @@ public class PolicyController {
             return new ResponseEntity<>("Policy type not found", HttpStatus.NOT_FOUND);
         }
         if ((ric != null && this.rics.get(ric) == null)) {
-            return new ResponseEntity<>("RIC not found", HttpStatus.NOT_FOUND);
+            return new ResponseEntity<>("NearRT-RIC not found", HttpStatus.NOT_FOUND);
         }
 
         String filteredPolicies = policiesToJson(filter(type, ric, service));
@@ -342,11 +345,11 @@ public class PolicyController {
     @ApiOperation(value = "Query policies, only IDs returned")
     @ApiResponses(
         value = {@ApiResponse(code = 200, message = "Policy ids", response = String.class, responseContainer = "List"),
-            @ApiResponse(code = 404, message = "RIC or type not found", response = String.class)})
+            @ApiResponse(code = 404, message = "NearRT-RIC or type not found", response = String.class)})
     public ResponseEntity<String> getPolicyIds( //
         @ApiParam(name = "type", required = false, value = "The name of the policy type to get policies for.") //
         @RequestParam(name = "type", required = false) String type, //
-        @ApiParam(name = "ric", required = false, value = "The name of the Near-RT RIC to get policies for.") //
+        @ApiParam(name = "ric", required = false, value = "The name of the NearRT-RIC to get policies for.") //
         @RequestParam(name = "ric", required = false) String ric, //
         @ApiParam(name = "service", required = false, value = "The name of the service to get policies for.") //
         @RequestParam(name = "service", required = false) String service) //
@@ -355,7 +358,7 @@ public class PolicyController {
             return new ResponseEntity<>("Policy type not found", HttpStatus.NOT_FOUND);
         }
         if ((ric != null && this.rics.get(ric) == null)) {
-            return new ResponseEntity<>("RIC not found", HttpStatus.NOT_FOUND);
+            return new ResponseEntity<>("NearRT-RIC not found", HttpStatus.NOT_FOUND);
         }
 
         String policyIdsJson = toPolicyIdsJson(filter(type, ric, service));
@@ -370,7 +373,7 @@ public class PolicyController {
             @ApiResponse(code = 404, message = "Policy is not found", response = String.class)} //
     )
     public Mono<ResponseEntity<String>> getPolicyStatus( //
-        @ApiParam(name = "id", required = true, value = "The ID of the policy.") @RequestParam(
+        @ApiParam(name = "id", required = true, value = "The identity of the policy.") @RequestParam(
             name = "id", //
             required = true) String id) {
         try {
@@ -402,8 +405,7 @@ public class PolicyController {
         }
         List<Policy> filtered = new ArrayList<>();
         for (Policy p : collection) {
-            if (include(type, p.type().name()) && include(ric, p.ric().name())
-                && include(service, p.ownerServiceName())) {
+            if (include(type, p.type().id()) && include(ric, p.ric().id()) && include(service, p.ownerServiceId())) {
                 filtered.add(p);
             }
         }
@@ -428,10 +430,10 @@ public class PolicyController {
             PolicyInfo policyInfo = new PolicyInfo();
             policyInfo.id = p.id();
             policyInfo.json = fromJson(p.json());
-            policyInfo.ric = p.ric().name();
-            policyInfo.type = p.type().name();
-            policyInfo.service = p.ownerServiceName();
-            policyInfo.lastModified = p.lastModified();
+            policyInfo.ric = p.ric().id();
+            policyInfo.type = p.type().id();
+            policyInfo.service = p.ownerServiceId();
+            policyInfo.lastModified = p.lastModified().toString();
             if (!policyInfo.validate()) {
                 logger.error("BUG, all fields must be set");
             }
@@ -462,7 +464,7 @@ public class PolicyController {
     private String toPolicyTypeIdsJson(Collection<PolicyType> types) {
         List<String> v = new ArrayList<>(types.size());
         for (PolicyType t : types) {
-            v.add(t.name());
+            v.add(t.id());
         }
         return gson.toJson(v);
     }
@@ -475,8 +477,4 @@ public class PolicyController {
         return gson.toJson(v);
     }
 
-    private String getTimeStampUtc() {
-        return java.time.Instant.now().toString();
-    }
-
 }
@@ -18,7 +18,7 @@
  * ========================LICENSE_END===================================
  */
 
-package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -26,7 +26,7 @@ import io.swagger.annotations.ApiModelProperty;
 import org.immutables.gson.Gson;
 
 @Gson.TypeAdapters
-@ApiModel(value = "PolicyInfo")
+@ApiModel(value = "policy_info_v1")
 public class PolicyInfo {
 
     @ApiModelProperty(value = "identity of the policy")
@@ -35,7 +35,7 @@ public class PolicyInfo {
     @ApiModelProperty(value = "name of the policy type")
     public String type;
 
-    @ApiModelProperty(value = "identity of the target Near-RT RIC")
+    @ApiModelProperty(value = "identity of the target NearRT-RIC")
     public String ric;
 
     @ApiModelProperty(value = "the configuration of the policy")
@@ -18,7 +18,7 @@
  * ========================LICENSE_END===================================
  */
 
-package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -28,9 +28,9 @@ import java.util.Collection;
 import org.immutables.gson.Gson;
 
 @Gson.TypeAdapters
-@ApiModel(value = "RicInfo")
+@ApiModel(value = "ric_info_v1")
 class RicInfo {
-    @ApiModelProperty(value = "identity of the ric")
+    @ApiModelProperty(value = "identity of the NearRT-RIC")
     public final String ricName;
 
     @ApiModelProperty(value = "O1 identities for managed entities")
@@ -18,7 +18,7 @@
  * ========================LICENSE_END===================================
  */
 
-package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -44,7 +44,7 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
-@Api(tags = "RIC Repository")
+@Api(tags = Consts.V1_API_NAME)
 public class RicRepositoryController {
 
     @Autowired
@@ -64,16 +64,16 @@ public class RicRepositoryController {
     @ApiOperation(value = "Returns the name of a RIC managing one Mananged Element")
     @ApiResponses(
         value = { //
-            @ApiResponse(code = 200, message = "RIC is found", response = String.class), //
-            @ApiResponse(code = 404, message = "RIC is not found", response = String.class) //
+            @ApiResponse(code = 200, message = "NearRT-RIC is found", response = String.class), //
+            @ApiResponse(code = 404, message = "NearRT-RIC is not found", response = String.class) //
         })
     public ResponseEntity<String> getRic( //
-        @ApiParam(name = "managedElementId", required = true, value = "The ID of the Managed Element") //
+        @ApiParam(name = "managedElementId", required = true, value = "The identity of the Managed Element") //
         @RequestParam(name = "managedElementId", required = true) String managedElementId) {
         Optional<Ric> ric = this.rics.lookupRicForManagedElement(managedElementId);
 
         if (ric.isPresent()) {
-            return new ResponseEntity<>(ric.get().name(), HttpStatus.OK);
+            return new ResponseEntity<>(ric.get().id(), HttpStatus.OK);
         } else {
             return new ResponseEntity<>("No RIC found", HttpStatus.NOT_FOUND);
         }
@@ -83,7 +83,7 @@ public class RicRepositoryController {
      * @return a Json array of all RIC data Example: http://localhost:8081/ric
      */
     @GetMapping("/rics")
-    @ApiOperation(value = "Query Near-RT RIC information")
+    @ApiOperation(value = "Query NearRT-RIC information")
     @ApiResponses(
         value = { //
             @ApiResponse(code = 200, message = "OK", response = RicInfo.class, responseContainer = "List"), //
@@ -98,7 +98,7 @@ public class RicRepositoryController {
         List<RicInfo> result = new ArrayList<>();
         for (Ric ric : rics.getRics()) {
             if (supportingPolicyType == null || ric.isSupportingType(supportingPolicyType)) {
-                result.add(new RicInfo(ric.name(), ric.getManagedElementIds(), ric.getSupportedPolicyTypeNames(),
+                result.add(new RicInfo(ric.id(), ric.getManagedElementIds(), ric.getSupportedPolicyTypeNames(),
                     ric.getState().toString()));
             }
         }
@@ -18,7 +18,7 @@
  * ========================LICENSE_END===================================
  */
 
-package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -35,6 +35,7 @@ import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collection;
 
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.VoidResponse;
 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
@@ -51,7 +52,7 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
-@Api(tags = "Service registry and supervision")
+@Api(tags = Consts.V1_API_NAME)
 public class ServiceController {
 
     private final Services services;
@@ -130,7 +131,8 @@ public class ServiceController {
     @ApiOperation(value = "Delete a service")
     @ApiResponses(
         value = { //
-            @ApiResponse(code = 204, message = "OK"),
+            @ApiResponse(code = 204, message = "Service deleted"),
+            @ApiResponse(code = 204, message = "Not used", response = VoidResponse.class),
             @ApiResponse(code = 404, message = "Service not found", response = String.class)})
     @DeleteMapping("/services")
     public ResponseEntity<String> deleteService(//
@@ -18,7 +18,7 @@
  * ========================LICENSE_END===================================
  */
 
-package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
 
 import com.google.gson.annotations.SerializedName;
 
@@ -28,12 +28,10 @@ import io.swagger.annotations.ApiModelProperty;
 import org.immutables.gson.Gson;
 
 @Gson.TypeAdapters
-@ApiModel(value = "ServiceRegistrationInfo")
+@ApiModel(value = "service_registration_info_v1")
 public class ServiceRegistrationInfo {
 
-    @ApiModelProperty(value = "identity of the service", required = true, allowEmptyValue = false)
-    @SerializedName(value = "serviceName", alternate = {"name"})
-
+    @SerializedName("serviceName")
     public String serviceName = "";
 
     @ApiModelProperty(
@@ -18,7 +18,7 @@
  * ========================LICENSE_END===================================
  */
 
-package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -26,7 +26,7 @@ import io.swagger.annotations.ApiModelProperty;
 import org.immutables.gson.Gson;
 
 @Gson.TypeAdapters
-@ApiModel(value = "ServiceStatus")
+@ApiModel(value = "service_status_v1")
 public class ServiceStatus {
 
     @ApiModelProperty(value = "identity of the service")
@@ -18,7 +18,7 @@
  * ========================LICENSE_END===================================
  */
 
-package org.onap.ccsdk.oran.a1policymanagementservice.controllers;
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -32,7 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
 import reactor.core.publisher.Mono;
 
 @RestController
-@Api(tags = "Health check")
+@Api(tags = Consts.V1_API_NAME)
 public class StatusController {
 
     @GetMapping("/status")
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/Consts.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/Consts.java
new file mode 100644 (file)
index 0000000..68c1d71
--- /dev/null
@@ -0,0 +1,36 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+public class Consts {
+    public static final String RIC_ID_PARAM = "ric_id";
+    public static final String POLICY_TYPE_ID_PARAM = "policytype_id";
+    public static final String POLICY_ID_PARAM = "policy_id";
+    public static final String SERVICE_ID_PARAM = "service_id";
+    public static final String TRANSIENT_PARAM = "transient";
+    public static final String MANAGED_ELEMENT_ID_PARAM = "managed_element_id";
+
+    public static final String V2_API_ROOT = "/v2";
+    public static final String V2_API_NAME = "A1 Policy Management Version 2.0 (in progress)";
+
+    private Consts() {
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ErrorResponse.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ErrorResponse.java
new file mode 100644 (file)
index 0000000..2ba63ab
--- /dev/null
@@ -0,0 +1,106 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import reactor.core.publisher.Mono;
+
+class ErrorResponse {
+    private static Gson gson = new GsonBuilder() //
+        .create(); //
+
+    // Returned as body for all failed REST calls
+    @ApiModel(value = "error_information", description = "Problem as defined in https://tools.ietf.org/html/rfc7807")
+    public static class ErrorInfo {
+        @SerializedName("type")
+        private String type = "about:blank";
+
+        @SerializedName("title")
+        private String title = null;
+
+        @SerializedName("status")
+        private final Integer status;
+
+        @SerializedName("detail")
+        private String detail = null;
+
+        @SerializedName("instance")
+        private String instance = null;
+
+        public ErrorInfo(String detail, Integer status) {
+            this.detail = detail;
+            this.status = status;
+        }
+
+        @ApiModelProperty(
+            example = "503",
+            value = "The HTTP status code generated by the origin server for this occurrence of the problem. ")
+        public Integer getStatus() {
+            return status;
+        }
+
+        @ApiModelProperty(
+            example = "Policy type not found",
+            value = " A human-readable explanation specific to this occurrence of the problem.")
+        public String getDetail() {
+            return this.detail;
+        }
+
+    }
+
+    @ApiModelProperty(value = "message")
+    public final String message;
+
+    ErrorResponse(String message) {
+        this.message = message;
+    }
+
+    static Mono<ResponseEntity<Object>> createMono(String text, HttpStatus code) {
+        return Mono.just(create(text, code));
+    }
+
+    static Mono<ResponseEntity<Object>> createMono(Exception e, HttpStatus code) {
+        return createMono(e.toString(), code);
+    }
+
+    static ResponseEntity<Object> create(String text, HttpStatus code) {
+        ErrorInfo p = new ErrorInfo(text, code.value());
+        String json = gson.toJson(p);
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_PROBLEM_JSON);
+        return new ResponseEntity<>(json, headers, code);
+    }
+
+    static ResponseEntity<Object> create(Exception e, HttpStatus code) {
+        return create(e.toString(), code);
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/JsonObject.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/JsonObject.java
new file mode 100644 (file)
index 0000000..9290ca0
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import io.swagger.annotations.ApiModel;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "json_object", description = "A JSON object. The schema is defined by the Policy Type")
+class JsonObject {
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/JsonSchema.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/JsonSchema.java
new file mode 100644 (file)
index 0000000..ff1b8ed
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import io.swagger.annotations.ApiModel;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "json_schema", description = "A JSON schema following http://json-schema.org/draft-07/schema")
+class JsonSchema {
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java
new file mode 100644 (file)
index 0000000..9bf6c4b
--- /dev/null
@@ -0,0 +1,516 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.lang.invoke.MethodHandles;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import lombok.Getter;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.VoidResponse;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+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.WebClientResponseException;
+import reactor.core.publisher.Mono;
+
+@RestController("PolicyControllerV2")
+@Api(tags = Consts.V2_API_NAME)
+public class PolicyController {
+
+    public static class RejectionException extends Exception {
+        private static final long serialVersionUID = 1L;
+
+        @Getter
+        private final HttpStatus status;
+
+        public RejectionException(String message, HttpStatus status) {
+            super(message);
+            this.status = status;
+        }
+    }
+
+    @Autowired
+    private Rics rics;
+    @Autowired
+    private PolicyTypes policyTypes;
+    @Autowired
+    private Policies policies;
+    @Autowired
+    private A1ClientFactory a1ClientFactory;
+    @Autowired
+    private Services services;
+
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+    private static Gson gson = new GsonBuilder() //
+        .serializeNulls() //
+        .create(); //
+
+    @GetMapping(path = Consts.V2_API_ROOT + "/policy-schemas", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Returns policy type schema definitions")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Policy schemas", response = PolicySchemaList.class), //
+            @ApiResponse(code = 404, message = "NearRT-RIC is not found", response = ErrorResponse.ErrorInfo.class)})
+    public ResponseEntity<Object> getPolicySchemas( //
+        @ApiParam(
+            name = Consts.RIC_ID_PARAM,
+            required = false,
+            value = "The identity of the NearRT-RIC to get the definitions for.") //
+        @RequestParam(name = Consts.RIC_ID_PARAM, required = false) String ricId,
+        @ApiParam(
+            name = Consts.POLICY_TYPE_ID_PARAM,
+            required = true,
+            value = "The identity of the policy type to get the definition for. When this parameter is given, max one schema will be returned") //
+        @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false) String policyTypeId) {
+        try {
+            if (ricId == null && policyTypeId == null) {
+                Collection<PolicyType> types = this.policyTypes.getAll();
+                return new ResponseEntity<>(toPolicyTypeSchemasJson(types), HttpStatus.OK);
+            } else if (ricId != null && policyTypeId != null) {
+                Collection<PolicyType> types = new ArrayList<>();
+                if (rics.getRic(ricId).isSupportingType(policyTypeId)) {
+                    types.add(policyTypes.getType(policyTypeId));
+                }
+                return new ResponseEntity<>(toPolicyTypeSchemasJson(types), HttpStatus.OK);
+            } else if (ricId != null) {
+                Collection<PolicyType> types = rics.getRic(ricId).getSupportedPolicyTypes();
+                return new ResponseEntity<>(toPolicyTypeSchemasJson(types), HttpStatus.OK);
+            } else {
+                Collection<PolicyType> types = new ArrayList<>();
+                types.add(policyTypes.getType(policyTypeId));
+                return new ResponseEntity<>(toPolicyTypeSchemasJson(types), HttpStatus.OK);
+            }
+        } catch (ServiceException e) {
+            return ErrorResponse.create(e, HttpStatus.NOT_FOUND);
+        }
+    }
+
+    @GetMapping(path = Consts.V2_API_ROOT + "/policy-types", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Query policy type identities", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiResponses(
+        value = {@ApiResponse(code = 200, message = "Policy type IDs", response = PolicyTypeIdList.class),
+            @ApiResponse(code = 404, message = "NearRT-RIC is not found", response = ErrorResponse.ErrorInfo.class)})
+    public ResponseEntity<Object> getPolicyTypes( //
+        @ApiParam(
+            name = Consts.RIC_ID_PARAM,
+            required = false,
+            value = "The identity of the NearRT-RIC to get types for.") //
+        @RequestParam(name = Consts.RIC_ID_PARAM, required = false) String ricId) {
+        if (ricId == null) {
+            Collection<PolicyType> types = this.policyTypes.getAll();
+            return new ResponseEntity<>(toPolicyTypeIdsJson(types), HttpStatus.OK);
+        } else {
+            try {
+                Collection<PolicyType> types = rics.getRic(ricId).getSupportedPolicyTypes();
+                return new ResponseEntity<>(toPolicyTypeIdsJson(types), HttpStatus.OK);
+            } catch (ServiceException e) {
+                return ErrorResponse.create(e, HttpStatus.NOT_FOUND);
+            }
+        }
+    }
+
+    @GetMapping(path = Consts.V2_API_ROOT + "/policy", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Returns a policy configuration") //
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Policy found", response = JsonObject.class), //
+            @ApiResponse(code = 404, message = "Policy is not found", response = ErrorResponse.ErrorInfo.class)} //
+    )
+    public ResponseEntity<Object> getPolicy( //
+        @ApiParam(name = Consts.POLICY_ID_PARAM, required = true, value = "The identity of the policy instance.") //
+        @RequestParam(name = Consts.POLICY_ID_PARAM, required = true) String id) {
+        try {
+            Policy p = policies.getPolicy(id);
+            return new ResponseEntity<>(p.json(), HttpStatus.OK);
+        } catch (ServiceException e) {
+            return ErrorResponse.create(e, HttpStatus.NOT_FOUND);
+        }
+    }
+
+    @DeleteMapping(Consts.V2_API_ROOT + "/policy")
+    @ApiOperation(value = "Delete a policy")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Not used", response = VoidResponse.class),
+            @ApiResponse(code = 204, message = "Policy deleted", response = VoidResponse.class),
+            @ApiResponse(code = 404, message = "Policy is not found", response = ErrorResponse.ErrorInfo.class),
+            @ApiResponse(
+                code = 423,
+                message = "NearRT-RIC is not operational",
+                response = ErrorResponse.ErrorInfo.class)})
+    public Mono<ResponseEntity<Object>> deletePolicy( //
+        @ApiParam(name = Consts.POLICY_ID_PARAM, required = true, value = "The identity of the policy instance.") //
+        @RequestParam(name = Consts.POLICY_ID_PARAM, required = true) String id) {
+        try {
+            Policy policy = policies.getPolicy(id);
+            keepServiceAlive(policy.ownerServiceId());
+            Ric ric = policy.ric();
+            return ric.getLock().lock(LockType.SHARED) //
+                .flatMap(notUsed -> assertRicStateIdle(ric)) //
+                .flatMap(notUsed -> a1ClientFactory.createA1Client(policy.ric())) //
+                .doOnNext(notUsed -> policies.remove(policy)) //
+                .flatMap(client -> client.deletePolicy(policy)) //
+                .doOnNext(notUsed -> ric.getLock().unlockBlocking()) //
+                .doOnError(notUsed -> ric.getLock().unlockBlocking()) //
+                .flatMap(notUsed -> Mono.just(new ResponseEntity<>(HttpStatus.NO_CONTENT)))
+                .onErrorResume(this::handleException);
+        } catch (ServiceException e) {
+            return ErrorResponse.createMono(e, HttpStatus.NOT_FOUND);
+        }
+    }
+
+    @PutMapping(path = Consts.V2_API_ROOT + "/policy", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Create or update a policy")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 201, message = "Policy created", response = VoidResponse.class), //
+            @ApiResponse(code = 200, message = "Policy updated", response = VoidResponse.class), //
+            @ApiResponse(
+                code = 423,
+                message = "NearRT-RIC is not operational",
+                response = ErrorResponse.ErrorInfo.class), //
+            @ApiResponse(
+                code = 404,
+                message = "NearRT-RIC or policy type is not found",
+                response = ErrorResponse.ErrorInfo.class) //
+        })
+    public Mono<ResponseEntity<Object>> putPolicy( //
+        @ApiParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false, value = "The identity of the policy type.") //
+        @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false, defaultValue = "") String policyTypeId, //
+        @ApiParam(name = Consts.POLICY_ID_PARAM, required = true, value = "The identity of the policy instance.") //
+        @RequestParam(name = Consts.POLICY_ID_PARAM, required = true) String instanceId, //
+        @ApiParam(
+            name = Consts.RIC_ID_PARAM,
+            required = true,
+            value = "The identity of the NearRT-RIC where the policy will be " + //
+                "created.") //
+        @RequestParam(name = Consts.RIC_ID_PARAM, required = true) String ricId, //
+        @ApiParam(
+            name = Consts.SERVICE_ID_PARAM,
+            required = true,
+            value = "The identity of the service creating the policy.") //
+        @RequestParam(name = Consts.SERVICE_ID_PARAM, required = true) String serviceId, //
+        @ApiParam(
+            name = Consts.TRANSIENT_PARAM,
+            required = false,
+            value = "If the policy is transient or not (boolean " + //
+                "defaulted to false). A policy is transient if it will not be recreated in the NearRT-RIC " + //
+                "when it has been lost (for instance due to a restart)") //
+        @RequestParam(name = Consts.TRANSIENT_PARAM, required = false, defaultValue = "false") boolean isTransient, //
+        @RequestBody Object jsonBody) {
+
+        String jsonString = gson.toJson(jsonBody);
+        Ric ric = rics.get(ricId);
+        PolicyType type = policyTypes.get(policyTypeId);
+        keepServiceAlive(serviceId);
+        if (ric == null || type == null) {
+            return ErrorResponse.createMono("NearRT-RIC or policy type not found", HttpStatus.NOT_FOUND);
+        }
+        Policy policy = ImmutablePolicy.builder() //
+            .id(instanceId) //
+            .json(jsonString) //
+            .type(type) //
+            .ric(ric) //
+            .ownerServiceId(serviceId) //
+            .lastModified(Instant.now()) //
+            .isTransient(isTransient) //
+            .build();
+
+        final boolean isCreate = this.policies.get(policy.id()) == null;
+
+        return ric.getLock().lock(LockType.SHARED) //
+            .flatMap(notUsed -> assertRicStateIdle(ric)) //
+            .flatMap(notUsed -> checkSupportedType(ric, type)) //
+            .flatMap(notUsed -> validateModifiedPolicy(policy)) //
+            .flatMap(notUsed -> a1ClientFactory.createA1Client(ric)) //
+            .flatMap(client -> client.putPolicy(policy)) //
+            .doOnNext(notUsed -> policies.put(policy)) //
+            .doOnNext(notUsed -> ric.getLock().unlockBlocking()) //
+            .doOnError(trowable -> ric.getLock().unlockBlocking()) //
+            .flatMap(notUsed -> Mono.just(new ResponseEntity<>(isCreate ? HttpStatus.CREATED : HttpStatus.OK))) //
+            .onErrorResume(this::handleException);
+    }
+
+    private Mono<ResponseEntity<Object>> handleException(Throwable throwable) {
+        if (throwable instanceof WebClientResponseException) {
+            WebClientResponseException e = (WebClientResponseException) throwable;
+            return ErrorResponse.createMono(e.getResponseBodyAsString(), e.getStatusCode());
+        } else if (throwable instanceof RejectionException) {
+            RejectionException e = (RejectionException) throwable;
+            return ErrorResponse.createMono(e.getMessage(), e.getStatus());
+        } else {
+            return ErrorResponse.createMono(throwable.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    private Mono<Object> validateModifiedPolicy(Policy policy) {
+        // Check that ric is not updated
+        Policy current = this.policies.get(policy.id());
+        if (current != null && !current.ric().id().equals(policy.ric().id())) {
+            RejectionException e = new RejectionException("Policy cannot change RIC, policyId: " + current.id() + //
+                ", RIC ID: " + current.ric().id() + //
+                ", new ID: " + policy.ric().id(), HttpStatus.CONFLICT);
+            logger.debug("Request rejected, {}", e.getMessage());
+            return Mono.error(e);
+        }
+        return Mono.just("{}");
+    }
+
+    private Mono<Object> checkSupportedType(Ric ric, PolicyType type) {
+        if (!ric.isSupportingType(type.id())) {
+            logger.debug("Request rejected, type not supported, RIC: {}", ric);
+            RejectionException e = new RejectionException("Type: " + type.id() + " not supported by RIC: " + ric.id(),
+                HttpStatus.NOT_FOUND);
+            return Mono.error(e);
+        }
+        return Mono.just("{}");
+    }
+
+    private Mono<Object> assertRicStateIdle(Ric ric) {
+        if (ric.getState() == Ric.RicState.AVAILABLE) {
+            return Mono.just("{}");
+        } else {
+            logger.debug("Request rejected RIC not IDLE, ric: {}", ric);
+            RejectionException e = new RejectionException(
+                "Ric is not operational, RIC name: " + ric.id() + ", state: " + ric.getState(), HttpStatus.LOCKED);
+            return Mono.error(e);
+        }
+    }
+
+    @GetMapping(path = Consts.V2_API_ROOT + "/policies", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(
+        value = "Query policies",
+        notes = "If several query parameters are defined, the policies matching all conditions are returned")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Policies", response = PolicyInfoList.class),
+            @ApiResponse(
+                code = 404,
+                message = "NearRT-RIC, policy type or service not found",
+                response = ErrorResponse.ErrorInfo.class)})
+    public ResponseEntity<Object> getPolicies( //
+        @ApiParam(
+            name = Consts.POLICY_TYPE_ID_PARAM,
+            required = false,
+            value = "The identity of the policy type to get policies for.") //
+        @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false) String type, //
+        @ApiParam(
+            name = Consts.RIC_ID_PARAM,
+            required = false,
+            value = "The identity of the NearRT-RIC to get policies for.") //
+        @RequestParam(name = Consts.RIC_ID_PARAM, required = false) String ric, //
+        @ApiParam(
+            name = Consts.SERVICE_ID_PARAM,
+            required = false,
+            value = "The identity of the service to get policies for.") //
+        @RequestParam(name = Consts.SERVICE_ID_PARAM, required = false) String service) //
+    {
+        if ((type != null && this.policyTypes.get(type) == null)) {
+            return ErrorResponse.create("Policy type not found", HttpStatus.NOT_FOUND);
+        }
+        if ((ric != null && this.rics.get(ric) == null)) {
+            return ErrorResponse.create("NearRT-RIC not found", HttpStatus.NOT_FOUND);
+        }
+
+        String filteredPolicies = policiesToJson(filter(type, ric, service));
+        return new ResponseEntity<>(filteredPolicies, HttpStatus.OK);
+    }
+
+    @GetMapping(path = Consts.V2_API_ROOT + "/policy-ids", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Query policies, only IDs returned")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Policy ids", response = PolicyIdList.class),
+            @ApiResponse(
+                code = 404,
+                message = "NearRT-RIC or type not found",
+                response = ErrorResponse.ErrorInfo.class)})
+    public ResponseEntity<Object> getPolicyIds( //
+        @ApiParam(
+            name = Consts.POLICY_TYPE_ID_PARAM,
+            required = false,
+            value = "The identity of the policy type to get policies for.") //
+        @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false) String policyTypeId, //
+        @ApiParam(
+            name = Consts.RIC_ID_PARAM,
+            required = false,
+            value = "The identity of the NearRT-RIC to get policies for.") //
+        @RequestParam(name = Consts.RIC_ID_PARAM, required = false) String ricId, //
+        @ApiParam(
+            name = Consts.SERVICE_ID_PARAM,
+            required = false,
+            value = "The identity of the service to get policies for.") //
+        @RequestParam(name = Consts.SERVICE_ID_PARAM, required = false) String serviceId) //
+    {
+        if ((policyTypeId != null && this.policyTypes.get(policyTypeId) == null)) {
+            return ErrorResponse.create("Policy type not found", HttpStatus.NOT_FOUND);
+        }
+        if ((ricId != null && this.rics.get(ricId) == null)) {
+            return ErrorResponse.create("NearRT-RIC not found", HttpStatus.NOT_FOUND);
+        }
+
+        String policyIdsJson = toPolicyIdsJson(filter(policyTypeId, ricId, serviceId));
+        return new ResponseEntity<>(policyIdsJson, HttpStatus.OK);
+    }
+
+    @GetMapping(path = Consts.V2_API_ROOT + "/policy-status", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Returns a policy status") //
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Policy status", response = JsonObject.class), //
+            @ApiResponse(code = 404, message = "Policy is not found", response = ErrorResponse.ErrorInfo.class)} //
+    )
+    public Mono<ResponseEntity<Object>> getPolicyStatus( //
+        @ApiParam(name = Consts.POLICY_ID_PARAM, required = true, value = "The identity of the policy.") //
+        @RequestParam(name = Consts.POLICY_ID_PARAM, required = true) String policyId) {
+        try {
+            Policy policy = policies.getPolicy(policyId);
+
+            return a1ClientFactory.createA1Client(policy.ric()) //
+                .flatMap(client -> client.getPolicyStatus(policy)) //
+                .flatMap(status -> Mono.just(new ResponseEntity<>((Object) status, HttpStatus.OK)))
+                .onErrorResume(this::handleException);
+        } catch (ServiceException e) {
+            return ErrorResponse.createMono(e, HttpStatus.NOT_FOUND);
+        }
+    }
+
+    private void keepServiceAlive(String name) {
+        Service s = this.services.get(name);
+        if (s != null) {
+            s.keepAlive();
+        }
+    }
+
+    private boolean include(String filter, String value) {
+        return filter == null || value.equals(filter);
+    }
+
+    private Collection<Policy> filter(Collection<Policy> collection, String type, String ric, String service) {
+        if (type == null && ric == null && service == null) {
+            return collection;
+        }
+        List<Policy> filtered = new ArrayList<>();
+        for (Policy p : collection) {
+            if (include(type, p.type().id()) && include(ric, p.ric().id()) && include(service, p.ownerServiceId())) {
+                filtered.add(p);
+            }
+        }
+        return filtered;
+    }
+
+    private Collection<Policy> filter(String type, String ric, String service) {
+        if (type != null) {
+            return filter(policies.getForType(type), null, ric, service);
+        } else if (service != null) {
+            return filter(policies.getForService(service), type, ric, null);
+        } else if (ric != null) {
+            return filter(policies.getForRic(ric), type, null, service);
+        } else {
+            return policies.getAll();
+        }
+    }
+
+    private String policiesToJson(Collection<Policy> policies) {
+        List<PolicyInfo> v = new ArrayList<>(policies.size());
+        for (Policy p : policies) {
+            PolicyInfo policyInfo = new PolicyInfo();
+            policyInfo.policyId = p.id();
+            policyInfo.policyData = fromJson(p.json());
+            policyInfo.ricId = p.ric().id();
+            policyInfo.policyTypeId = p.type().id();
+            policyInfo.serviceId = p.ownerServiceId();
+            policyInfo.lastModified = p.lastModified().toString();
+            if (!policyInfo.validate()) {
+                logger.error("BUG, all fields must be set");
+            }
+            v.add(policyInfo);
+        }
+        PolicyInfoList list = new PolicyInfoList(v);
+        return gson.toJson(list);
+    }
+
+    private Object fromJson(String jsonStr) {
+        return gson.fromJson(jsonStr, Object.class);
+    }
+
+    private String toPolicyTypeSchemasJson(Collection<PolicyType> types) {
+
+        Collection<String> schemas = new ArrayList<>();
+        for (PolicyType t : types) {
+            schemas.add(t.schema());
+        }
+        PolicySchemaList res = new PolicySchemaList(schemas);
+        return gson.toJson(res);
+    }
+
+    private String toPolicyTypeIdsJson(Collection<PolicyType> types) {
+        List<String> v = new ArrayList<>(types.size());
+        for (PolicyType t : types) {
+            v.add(t.id());
+        }
+        PolicyTypeIdList ids = new PolicyTypeIdList(v);
+        return gson.toJson(ids);
+    }
+
+    private String toPolicyIdsJson(Collection<Policy> policies) {
+        List<String> v = new ArrayList<>(policies.size());
+        for (Policy p : policies) {
+            v.add(p.id());
+        }
+        return gson.toJson(new PolicyIdList(v));
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyIdList.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyIdList.java
new file mode 100644 (file)
index 0000000..329ce5f
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Collection;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "policy_id_list_v2", description = "A list of policy identities")
+public class PolicyIdList {
+
+    @ApiModelProperty(value = "Policy identities")
+    @SerializedName("policy_ids")
+    @JsonProperty("policy_ids")
+    public final Collection<String> policyIds;
+
+    public PolicyIdList(Collection<String> ids) {
+        this.policyIds = ids;
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java
new file mode 100644 (file)
index 0000000..4ba3dc7
--- /dev/null
@@ -0,0 +1,73 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "policy_info_v2", description = "Information for one A1-P Policy")
+public class PolicyInfo {
+
+    @ApiModelProperty(value = "identity of the policy")
+    @JsonProperty("policy_id")
+    @SerializedName("policy_id")
+    public String policyId;
+
+    @ApiModelProperty(value = "name of the policy type")
+    @SerializedName("policy_type_id")
+    @JsonProperty("policy_type_id")
+    public String policyTypeId;
+
+    @ApiModelProperty(value = "identity of the target NearRT-RIC")
+    @SerializedName("ric_id")
+    @JsonProperty("ric_id")
+    public String ricId;
+
+    @ApiModelProperty(value = "the configuration of the policy")
+    @SerializedName("policy_data")
+    @JsonProperty("policy_data")
+    public Object policyData;
+
+    @ApiModelProperty(value = "the name of the service owning the policy")
+    @SerializedName("service_id")
+    @JsonProperty("service_id")
+    public String serviceId;
+
+    @ApiModelProperty(value = "timestamp, last modification time")
+    @SerializedName("last_modified")
+    @JsonProperty("last_modified")
+    public String lastModified;
+
+    PolicyInfo() {
+    }
+
+    public boolean validate() {
+        return policyId != null && policyTypeId != null && ricId != null && policyData != null && serviceId != null
+            && lastModified != null;
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfoList.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfoList.java
new file mode 100644 (file)
index 0000000..dde00a5
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Collection;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "policy_info_list_v2", description = "List of policy information")
+public class PolicyInfoList {
+
+    @ApiModelProperty(value = "List of policy information")
+    @SerializedName("policies")
+    @JsonProperty("policies")
+    public final Collection<PolicyInfo> policies;
+
+    public PolicyInfoList(Collection<PolicyInfo> policies) {
+        this.policies = policies;
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicySchemaList.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicySchemaList.java
new file mode 100644 (file)
index 0000000..66296f5
--- /dev/null
@@ -0,0 +1,53 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "policy_schema_list_v2", description = "Policy type json schemas")
+public class PolicySchemaList {
+
+    @ApiModelProperty(value = "Policy type json schemas")
+    @SerializedName("policy_schemas")
+    @JsonProperty("policy_schemas")
+    public final Collection<Object> schemas;
+
+    public PolicySchemaList(Collection<String> schemasAsStrings) {
+        this.schemas = new ArrayList<>();
+        for (String str : schemasAsStrings) {
+            JsonObject jsonObj = JsonParser.parseString(str).getAsJsonObject();
+            this.schemas.add(jsonObj);
+        }
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeIdList.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeIdList.java
new file mode 100644 (file)
index 0000000..5ecc727
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Collection;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "policy_type_id_list_v2", description = "Information about policy types")
+public class PolicyTypeIdList {
+
+    @ApiModelProperty(value = "Policy type identities")
+    @SerializedName("policy_type_ids")
+    @JsonProperty("policy_type_ids")
+    public final Collection<String> policyTypesIds;
+
+    public PolicyTypeIdList(Collection<String> ids) {
+        this.policyTypesIds = ids;
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfo.java
new file mode 100644 (file)
index 0000000..63b4bd6
--- /dev/null
@@ -0,0 +1,75 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Collection;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "ric_info_v2", description = "Information for a NearRT-RIC")
+public class RicInfo {
+
+    @Gson.TypeAdapters
+    @ApiModel(value = "ric_state_v2", description = "Represents the states for a NearRT-RIC")
+    public enum RicState {
+        UNAVAILABLE, AVAILABLE, SYNCHRONIZING, CONSISTENCY_CHECK
+    }
+
+    private static final String STATE_DESCRIPTION = "State for the NearRT-RIC, values: \n"
+        + "UNAVAILABLE: The NearRT-RIC is not avialable, information may be inconsistent \n"
+        + "AVAILABLE: The normal state. Policies can be configured. +\n"
+        + "SYNCHRONIZING: The Policy Management Service is synchronizing the view of the NearRT-RIC. Policies cannot be configured. \n"
+        + "CONSISTENCY_CHECK: A consistency check between the Policy Management Service and the NearRT-RIC. Policies cannot be configured.";
+
+    @ApiModelProperty(value = "identity of the NearRT-RIC")
+    @SerializedName("ric_id")
+    @JsonProperty("ric_id")
+    public final String ricId;
+
+    @ApiModelProperty(value = "O1 identities for managed entities")
+    @SerializedName("managed_element_ids")
+    @JsonProperty("managed_element_ids")
+    public final Collection<String> managedElementIds;
+
+    @ApiModelProperty(value = "supported policy types")
+    @SerializedName("policy_type_ids")
+    @JsonProperty("policy_type_ids")
+    public final Collection<String> policyTypeIds;
+
+    @ApiModelProperty(value = STATE_DESCRIPTION, name = "state")
+    @SerializedName("state")
+    @JsonProperty("state")
+    public final RicState state;
+
+    RicInfo(String ricId, Collection<String> managedElementIds, Collection<String> policyTypes, RicState state) {
+        this.ricId = ricId;
+        this.managedElementIds = managedElementIds;
+        this.policyTypeIds = policyTypes;
+        this.state = state;
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfoList.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfoList.java
new file mode 100644 (file)
index 0000000..7ca49be
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Collection;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "ric_info_list_v2", description = "List of NearRT-RIC information")
+public class RicInfoList {
+
+    @ApiModelProperty(value = "List of NearRT-RIC information")
+    @SerializedName("rics")
+    @JsonProperty("rics")
+    public final Collection<RicInfo> rics;
+
+    public RicInfoList(Collection<RicInfo> rics) {
+        this.rics = rics;
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicRepositoryController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicRepositoryController.java
new file mode 100644 (file)
index 0000000..a0987ad
--- /dev/null
@@ -0,0 +1,150 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController("RicRepositoryControllerV2")
+@Api(tags = Consts.V2_API_NAME)
+public class RicRepositoryController {
+
+    @Autowired
+    private Rics rics;
+
+    @Autowired
+    PolicyTypes types;
+
+    private static Gson gson = new GsonBuilder() //
+        .serializeNulls() //
+        .create(); //
+
+    /**
+     * Example: http://localhost:8081/v2/ric?managed_element_id=kista_1
+     */
+    @GetMapping(path = Consts.V2_API_ROOT + "/ric", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Returns info for the NearRT-RIC with the given identity or managing one Mananged Element")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "NearRT-RIC is found", response = RicInfo.class), //
+            @ApiResponse(code = 404, message = "NearRT-RIC is not found", response = ErrorResponse.ErrorInfo.class) //
+        })
+    public ResponseEntity<Object> getRic( //
+        @ApiParam(
+            name = Consts.MANAGED_ELEMENT_ID_PARAM,
+            required = false,
+            value = "The identity of a Managed Element. If given, the NearRT-RIC managing the ME is returned.") //
+        @RequestParam(name = Consts.MANAGED_ELEMENT_ID_PARAM, required = false) String managedElementId,
+        @ApiParam(
+            name = Consts.RIC_ID_PARAM,
+            required = false,
+            value = "The identity of a NearRT-RIC to get information for.") //
+        @RequestParam(name = Consts.RIC_ID_PARAM, required = false) String ricId) {
+        try {
+            if (managedElementId != null && ricId != null) {
+                return ErrorResponse.create("Give one query parameter", HttpStatus.BAD_REQUEST);
+            } else if (managedElementId != null) {
+                Optional<Ric> ric = this.rics.lookupRicForManagedElement(managedElementId);
+                if (ric.isPresent()) {
+                    return new ResponseEntity<>(gson.toJson(toRicInfo(ric.get())), HttpStatus.OK);
+                } else {
+                    return ErrorResponse.create("No NearRT-RIC managing the ME is found", HttpStatus.NOT_FOUND);
+                }
+            } else if (ricId != null) {
+                RicInfo info = toRicInfo(this.rics.getRic(ricId));
+                return new ResponseEntity<>(gson.toJson(info), HttpStatus.OK);
+            } else {
+                return ErrorResponse.create("Give one query parameter", HttpStatus.BAD_REQUEST);
+            }
+        } catch (ServiceException e) {
+            return ErrorResponse.create(e, HttpStatus.NOT_FOUND);
+        }
+    }
+
+    /**
+     * @return a Json array of all RIC data Example: http://localhost:8081/v2/ric
+     */
+    @GetMapping(path = Consts.V2_API_ROOT + "/rics", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Query NearRT-RIC information")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "OK", response = RicInfoList.class), //
+            @ApiResponse(code = 404, message = "Policy type is not found", response = ErrorResponse.ErrorInfo.class)})
+    public ResponseEntity<Object> getRics( //
+        @ApiParam(
+            name = Consts.POLICY_TYPE_ID_PARAM,
+            required = false,
+            value = "The identity of a policy type. If given, all NearRT-RICs supporteing the policy type are returned") //
+        @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false) String supportingPolicyType) {
+        if ((supportingPolicyType != null) && (this.types.get(supportingPolicyType) == null)) {
+            return ErrorResponse.create("Policy type not found", HttpStatus.NOT_FOUND);
+        }
+
+        List<RicInfo> result = new ArrayList<>();
+        for (Ric ric : rics.getRics()) {
+            if (supportingPolicyType == null || ric.isSupportingType(supportingPolicyType)) {
+                result.add(toRicInfo(ric));
+            }
+        }
+
+        return new ResponseEntity<>(gson.toJson(new RicInfoList(result)), HttpStatus.OK);
+    }
+
+    private RicInfo.RicState toRicState(Ric.RicState state) {
+        if (state == Ric.RicState.AVAILABLE) {
+            return RicInfo.RicState.AVAILABLE;
+        } else if (state == Ric.RicState.CONSISTENCY_CHECK) {
+            return RicInfo.RicState.CONSISTENCY_CHECK;
+        } else if (state == Ric.RicState.SYNCHRONIZING) {
+            return RicInfo.RicState.SYNCHRONIZING;
+        } else if (state == Ric.RicState.UNAVAILABLE) {
+            return RicInfo.RicState.UNAVAILABLE;
+        }
+        return RicInfo.RicState.UNAVAILABLE;
+    }
+
+    private RicInfo toRicInfo(Ric ric) {
+        return new RicInfo(ric.id(), ric.getManagedElementIds(), ric.getSupportedPolicyTypeNames(),
+            toRicState(ric.getState()));
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceController.java
new file mode 100644 (file)
index 0000000..19d6816
--- /dev/null
@@ -0,0 +1,194 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.VoidResponse;
+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.Service;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+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;
+
+@RestController("ServiceControllerV2")
+@Api(tags = Consts.V2_API_NAME)
+public class ServiceController {
+
+    private final Services services;
+    private final Policies policies;
+
+    private static Gson gson = new GsonBuilder() //
+        .create(); //
+
+    @Autowired
+    ServiceController(Services services, Policies policies) {
+        this.services = services;
+        this.policies = policies;
+    }
+
+    @GetMapping(path = Consts.V2_API_ROOT + "/services", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Returns service information")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "OK", response = ServiceStatusList.class), //
+            @ApiResponse(code = 404, message = "Service is not found", response = ErrorResponse.ErrorInfo.class)})
+    public ResponseEntity<Object> getServices(//
+        @ApiParam(name = Consts.SERVICE_ID_PARAM, required = false, value = "The identity of the service") //
+        @RequestParam(name = Consts.SERVICE_ID_PARAM, required = false) String name) {
+        if (name != null && this.services.get(name) == null) {
+            return ErrorResponse.create("Service type not found", HttpStatus.NOT_FOUND);
+        }
+
+        Collection<ServiceStatus> servicesStatus = new ArrayList<>();
+        for (Service s : this.services.getAll()) {
+            if (name == null || name.equals(s.getName())) {
+                servicesStatus.add(toServiceStatus(s));
+            }
+        }
+
+        String res = gson.toJson(new ServiceStatusList(servicesStatus));
+        return new ResponseEntity<>(res, HttpStatus.OK);
+    }
+
+    private ServiceStatus toServiceStatus(Service s) {
+        return new ServiceStatus(s.getName(), s.getKeepAliveInterval().toSeconds(), s.timeSinceLastPing().toSeconds(),
+            s.getCallbackUrl());
+    }
+
+    private void validateRegistrationInfo(ServiceRegistrationInfo registrationInfo)
+        throws ServiceException, MalformedURLException {
+        if (registrationInfo.serviceId.isEmpty()) {
+            throw new ServiceException("Missing mandatory parameter 'serviceName'");
+        }
+        if (registrationInfo.keepAliveIntervalSeconds < 0) {
+            throw new ServiceException("Keepalive interval shoul be greater or equal to 0");
+        }
+        if (!registrationInfo.callbackUrl.isEmpty()) {
+            new URL(registrationInfo.callbackUrl);
+        }
+    }
+
+    @ApiOperation(value = "Register a service")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Service updated"),
+            @ApiResponse(code = 201, message = "Service created"), //
+            @ApiResponse(
+                code = 400,
+                message = "The ServiceRegistrationInfo is not accepted",
+                response = ErrorResponse.ErrorInfo.class)})
+    @PutMapping(Consts.V2_API_ROOT + "/services")
+    public ResponseEntity<Object> putService(//
+        @RequestBody ServiceRegistrationInfo registrationInfo) {
+        try {
+            validateRegistrationInfo(registrationInfo);
+            final boolean isCreate = this.services.get(registrationInfo.serviceId) == null;
+            this.services.put(toService(registrationInfo));
+            return new ResponseEntity<>(isCreate ? HttpStatus.CREATED : HttpStatus.OK);
+        } catch (Exception e) {
+            return ErrorResponse.create(e, HttpStatus.BAD_REQUEST);
+        }
+    }
+
+    @ApiOperation(value = "Delete a service")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 204, message = "Service deleted"),
+            @ApiResponse(code = 200, message = "Not used", response = VoidResponse.class),
+            @ApiResponse(code = 404, message = "Service not found", response = ErrorResponse.ErrorInfo.class)})
+    @DeleteMapping(Consts.V2_API_ROOT + "/services")
+    public ResponseEntity<Object> deleteService(//
+        @ApiParam(name = Consts.SERVICE_ID_PARAM, required = true, value = "The name of the service") //
+        @RequestParam(name = Consts.SERVICE_ID_PARAM, required = true) String serviceName) {
+        try {
+            Service service = removeService(serviceName);
+            // Remove the policies from the repo and let the consistency monitoring
+            // do the rest.
+            removePolicies(service);
+            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        } catch (ServiceException e) {
+            return ErrorResponse.create(e, HttpStatus.NOT_FOUND);
+        }
+    }
+
+    @ApiOperation(value = "Heartbeat indicates that the service is running")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Service supervision timer refreshed, OK"), //
+            @ApiResponse(
+                code = 404,
+                message = "The service is not found, needs re-registration",
+                response = ErrorResponse.ErrorInfo.class)})
+
+    @PutMapping(Consts.V2_API_ROOT + "/services/keepalive")
+    public ResponseEntity<Object> keepAliveService(//
+        @ApiParam(name = Consts.SERVICE_ID_PARAM, required = true, value = "The identity of the service") //
+        @RequestParam(name = Consts.SERVICE_ID_PARAM, required = true) String serviceName) {
+        try {
+            services.getService(serviceName).keepAlive();
+            return new ResponseEntity<>(HttpStatus.OK);
+        } catch (ServiceException e) {
+            return ErrorResponse.create(e, HttpStatus.NOT_FOUND);
+        }
+    }
+
+    private Service removeService(String name) throws ServiceException {
+        Service service = this.services.getService(name); // Just to verify that it exists
+        this.services.remove(service.getName());
+        return service;
+    }
+
+    private void removePolicies(Service service) {
+        Collection<Policy> policyList = this.policies.getForService(service.getName());
+        for (Policy policy : policyList) {
+            this.policies.remove(policy);
+        }
+    }
+
+    private Service toService(ServiceRegistrationInfo s) {
+        return new Service(s.serviceId, Duration.ofSeconds(s.keepAliveIntervalSeconds), s.callbackUrl);
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceRegistrationInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceRegistrationInfo.java
new file mode 100644 (file)
index 0000000..30fcb7d
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "service_registration_info_v2", description = "Information for one service")
+public class ServiceRegistrationInfo {
+
+    @ApiModelProperty(value = "identity of the service", required = true, allowEmptyValue = false)
+    @SerializedName(value = "service_id")
+    @JsonProperty("service_id")
+    public String serviceId = "";
+
+    @ApiModelProperty(
+        value = "keep alive interval for the service. This is a heartbeat supervision of the service, "
+            + "which in regular intevals must invoke a 'keepAlive' REST call. "
+            + "When a service does not invoke this call within the given time, it is considered unavailble. "
+            + "An unavailable service will be automatically deregistered and its policies will be deleted. "
+            + "Value 0 means no timeout supervision.")
+    @SerializedName("keep_alive_interval_seconds")
+    @JsonProperty("keep_alive_interval_seconds")
+    public long keepAliveIntervalSeconds = 0;
+
+    @ApiModelProperty(value = "callback for notifying of RIC synchronization", required = false, allowEmptyValue = true)
+    @SerializedName("callback_url")
+    @JsonProperty("callback_url")
+    public String callbackUrl = "";
+
+    public ServiceRegistrationInfo() {
+    }
+
+    public ServiceRegistrationInfo(String id, long keepAliveIntervalSeconds, String callbackUrl) {
+        this.serviceId = id;
+        this.keepAliveIntervalSeconds = keepAliveIntervalSeconds;
+        this.callbackUrl = callbackUrl;
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceStatus.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceStatus.java
new file mode 100644 (file)
index 0000000..221fef8
--- /dev/null
@@ -0,0 +1,62 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "service_status_v2")
+public class ServiceStatus {
+
+    @ApiModelProperty(value = "identity of the service")
+    @SerializedName("service_id")
+    @JsonProperty("service_id")
+    public final String serviceId;
+
+    @ApiModelProperty(value = "policy keep alive timeout")
+    @SerializedName("keep_alive_interval_seconds")
+    @JsonProperty("keep_alive_interval_seconds")
+    public final long keepAliveIntervalSeconds;
+
+    @ApiModelProperty(value = "time since last invocation by the service")
+    @SerializedName("time_since_last_activity_seconds")
+    @JsonProperty("time_since_last_activity_seconds")
+    public final long timeSinceLastActivitySeconds;
+
+    @ApiModelProperty(value = "callback for notifying of RIC synchronization")
+    @SerializedName("callback_url")
+    @JsonProperty("callback_url")
+    public String callbackUrl;
+
+    ServiceStatus(String id, long keepAliveIntervalSeconds, long timeSincePingSeconds, String callbackUrl) {
+        this.serviceId = id;
+        this.keepAliveIntervalSeconds = keepAliveIntervalSeconds;
+        this.timeSinceLastActivitySeconds = timeSincePingSeconds;
+        this.callbackUrl = callbackUrl;
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceStatusList.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceStatusList.java
new file mode 100644 (file)
index 0000000..a7ffeca
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Collection;
+
+import org.immutables.gson.Gson;
+
+@Gson.TypeAdapters
+@ApiModel(value = "service_list_v2", description = "List of service information")
+public class ServiceStatusList {
+
+    @ApiModelProperty(value = "List of service information")
+    @SerializedName("service_list")
+    @JsonProperty("service_list")
+    public final Collection<ServiceStatus> statusList;
+
+    public ServiceStatusList(Collection<ServiceStatus> statuses) {
+        this.statusList = statuses;
+    }
+
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/StatusController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/StatusController.java
new file mode 100644 (file)
index 0000000..f47cdd5
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import org.immutables.gson.Gson;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
+
+@RestController("StatusControllerV2")
+@Api(tags = Consts.V2_API_NAME)
+public class StatusController {
+
+    @Gson.TypeAdapters
+    @ApiModel(value = "status_info_v2")
+    class StatusInfo {
+        @ApiModelProperty(value = "status text")
+        public final String status;
+
+        StatusInfo(String status) {
+            this.status = status;
+        }
+    }
+
+    @GetMapping(path = Consts.V2_API_ROOT + "/status", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ApiOperation(value = "Returns status and statistics of this service")
+    @ApiResponses(
+        value = { //
+            @ApiResponse(code = 200, message = "Service is living", response = StatusInfo.class) //
+        })
+    public Mono<ResponseEntity<Object>> getStatus() {
+        StatusInfo info = new StatusInfo("hunky dory");
+        return Mono.just(new ResponseEntity<>(info, HttpStatus.OK));
+    }
+
+}
index 3063a5f..37a092b 100644 (file)
@@ -111,7 +111,8 @@ public class DmaapMessageConsumer {
     protected boolean isDmaapConfigured() {
         String producerTopicUrl = applicationConfig.getDmaapProducerTopicUrl();
         String consumerTopicUrl = applicationConfig.getDmaapConsumerTopicUrl();
-        return (!producerTopicUrl.isEmpty() && !consumerTopicUrl.isEmpty());
+        return (producerTopicUrl != null && consumerTopicUrl != null && !producerTopicUrl.isEmpty()
+            && !consumerTopicUrl.isEmpty());
     }
 
     private static List<String> parseMessages(String jsonString) {
index 162d05f..4df2504 100644 (file)
@@ -37,9 +37,9 @@ public class Policies {
 
     public synchronized void put(Policy policy) {
         policiesId.put(policy.id(), policy);
-        multiMapPut(policiesRic, policy.ric().name(), policy);
-        multiMapPut(policiesService, policy.ownerServiceName(), policy);
-        multiMapPut(policiesType, policy.type().name(), policy);
+        multiMapPut(policiesRic, policy.ric().id(), policy);
+        multiMapPut(policiesService, policy.ownerServiceId(), policy);
+        multiMapPut(policiesType, policy.type().id(), policy);
     }
 
     private void multiMapPut(Map<String, Map<String, Policy>> multiMap, String key, Policy value) {
@@ -106,13 +106,13 @@ public class Policies {
 
     public synchronized void remove(Policy policy) {
         policiesId.remove(policy.id());
-        multiMapRemove(policiesRic, policy.ric().name(), policy);
-        multiMapRemove(policiesService, policy.ownerServiceName(), policy);
-        multiMapRemove(policiesType, policy.type().name(), policy);
+        multiMapRemove(policiesRic, policy.ric().id(), policy);
+        multiMapRemove(policiesService, policy.ownerServiceId(), policy);
+        multiMapRemove(policiesType, policy.type().id(), policy);
     }
 
-    public synchronized void removePoliciesForRic(String ricName) {
-        Collection<Policy> policiesForRic = getForRic(ricName);
+    public synchronized void removePoliciesForRic(String ricId) {
+        Collection<Policy> policiesForRic = getForRic(ricId);
         for (Policy policy : policiesForRic) {
             remove(policy);
         }
index 957b5f3..752d8da 100644 (file)
@@ -20,6 +20,8 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.repository;
 
+import java.time.Instant;
+
 import org.immutables.gson.Gson;
 import org.immutables.value.Value;
 
@@ -30,13 +32,13 @@ public interface Policy {
 
     public String json();
 
-    public String ownerServiceName();
+    public String ownerServiceId();
 
     public Ric ric();
 
     public PolicyType type();
 
-    public String lastModified();
+    public Instant lastModified();
 
     public boolean isTransient();
 }
index 9311e58..db25d9c 100644 (file)
@@ -43,7 +43,7 @@ public class PolicyTypes {
     }
 
     public synchronized void put(PolicyType type) {
-        types.put(type.name(), type);
+        types.put(type.id(), type);
     }
 
     public synchronized boolean contains(String policyType) {
index 14ac981..154809d 100644 (file)
@@ -30,10 +30,9 @@ import lombok.Setter;
 
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType;
 import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
-import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState;
 
 /**
- * Represents the dynamic information about a Near-RT RIC.
+ * Holds information about a NearRT-RIC.
  */
 public class Ric {
 
@@ -57,8 +56,8 @@ public class Ric {
         this.ricConfig = ricConfig;
     }
 
-    public String name() {
-        return ricConfig.name();
+    public String id() {
+        return ricConfig.ricId();
     }
 
     public RicConfig getConfig() {
@@ -111,7 +110,7 @@ public class Ric {
      * @param type the policy type to support.
      */
     public synchronized void addSupportedPolicyType(PolicyType type) {
-        supportedPolicyTypes.put(type.name(), type);
+        supportedPolicyTypes.put(type.id(), type);
     }
 
     /**
@@ -134,7 +133,7 @@ public class Ric {
 
     @Override
     public synchronized String toString() {
-        return Ric.class.getSimpleName() + ": " + "name: " + name() + ", state: " + state + ", baseUrl: "
+        return Ric.class.getSimpleName() + ": " + "name: " + id() + ", state: " + state + ", baseUrl: "
             + ricConfig.baseUrl() + ", managedNodes: " + ricConfig.managedElementIds();
     }
 
@@ -143,7 +142,7 @@ public class Ric {
      */
     public enum RicState {
         /**
-         * The Policy Management Service's view of the Ric may be inconsistent.
+         * The Policy Management Service's view of the NearRT-RIC may be inconsistent.
          */
         UNAVAILABLE,
         /**
@@ -151,12 +150,13 @@ public class Ric {
          */
         AVAILABLE,
         /**
-         * The Policy Management Service is synchronizing the view of the Ric.
+         * The Policy Management Service is synchronizing the view of the NearRT-RIC.
          */
         SYNCHRONIZING,
 
         /**
-         * A consistency check between the Policy Management Service and the Ric is done
+         * A consistency check between the Policy Management Service and the NearRT-RIC
+         * is done
          */
         CONSISTENCY_CHECK
     }
index d810dfa..75c16da 100644 (file)
@@ -35,27 +35,27 @@ public class Rics {
     Map<String, Ric> registeredRics = new HashMap<>();
 
     public synchronized void put(Ric ric) {
-        registeredRics.put(ric.name(), ric);
+        registeredRics.put(ric.id(), ric);
     }
 
     public synchronized Collection<Ric> getRics() {
         return new Vector<>(registeredRics.values());
     }
 
-    public synchronized Ric getRic(String name) throws ServiceException {
-        Ric ric = registeredRics.get(name);
+    public synchronized Ric getRic(String ricId) throws ServiceException {
+        Ric ric = registeredRics.get(ricId);
         if (ric == null) {
-            throw new ServiceException("Could not find ric: " + name);
+            throw new ServiceException("Could not find ric: " + ricId);
         }
         return ric;
     }
 
-    public synchronized Ric get(String name) {
-        return registeredRics.get(name);
+    public synchronized Ric get(String ricId) {
+        return registeredRics.get(ricId);
     }
 
-    public synchronized void remove(String name) {
-        registeredRics.remove(name);
+    public synchronized void remove(String ricId) {
+        registeredRics.remove(ricId);
     }
 
     public synchronized int size() {
index f113da9..57d6969 100644 (file)
@@ -68,7 +68,8 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 /**
- * Regularly refreshes the configuration from Consul or from a local configuration file.
+ * Regularly refreshes the configuration from Consul or from a local
+ * configuration file.
  */
 @Component
 public class RefreshConfigTask {
@@ -198,15 +199,15 @@ public class RefreshConfigTask {
 
     private void handleUpdatedRicConfig(RicConfigUpdate updatedInfo) {
         synchronized (this.rics) {
-            String ricName = updatedInfo.getRicConfig().name();
+            String ricId = updatedInfo.getRicConfig().ricId();
             RicConfigUpdate.Type event = updatedInfo.getType();
             if (event == RicConfigUpdate.Type.ADDED) {
                 addRic(updatedInfo.getRicConfig());
             } else if (event == RicConfigUpdate.Type.REMOVED) {
-                rics.remove(ricName);
-                this.policies.removePoliciesForRic(ricName);
+                rics.remove(ricId);
+                this.policies.removePoliciesForRic(ricId);
             } else if (event == RicConfigUpdate.Type.CHANGED) {
-                Ric ric = this.rics.get(ricName);
+                Ric ric = this.rics.get(ricId);
                 if (ric == null) {
                     // Should not happen,just for robustness
                     addRic(updatedInfo.getRicConfig());
index 832ec11..9bad36c 100644 (file)
@@ -44,7 +44,7 @@ import reactor.core.publisher.Mono;
 
 /**
  * Regularly checks the existing rics towards the local repository to keep it
- * consistent. When the policy types or instances in the Near-RT RIC is not
+ * consistent. When the policy types or instances in the NearRT-RIC is not
  * consistent, a synchronization is performed.
  */
 @Component
@@ -118,7 +118,7 @@ public class RicSupervision {
     }
 
     private void onRicCheckedError(Throwable t, RicData ricData) {
-        logger.debug("Ric: {} check stopped, exception: {}", ricData.ric.name(), t.getMessage());
+        logger.debug("Ric: {} check stopped, exception: {}", ricData.ric.id(), t.getMessage());
         if (t instanceof SynchStartedException) {
             // this is just a temporary state,
             ricData.ric.setState(RicState.AVAILABLE);
@@ -129,7 +129,7 @@ public class RicSupervision {
     }
 
     private void onRicCheckedOk(RicData ricData) {
-        logger.debug("Ric: {} checked OK", ricData.ric.name());
+        logger.debug("Ric: {} checked OK", ricData.ric.id());
         ricData.ric.setState(RicState.AVAILABLE);
         ricData.ric.getLock().unlockBlocking();
     }
@@ -138,7 +138,7 @@ public class RicSupervision {
     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().name());
+                logger.debug("Ric: {} is already being checked", ric.ric.getConfig().ricId());
                 return Mono.empty();
             }
             ric.ric.setState(RicState.CONSISTENCY_CHECK);
@@ -170,7 +170,7 @@ public class RicSupervision {
 
     private Mono<RicData> validateInstances(Collection<String> ricPolicies, RicData ric) {
         synchronized (this.policies) {
-            if (ricPolicies.size() != policies.getForRic(ric.ric.name()).size()) {
+            if (ricPolicies.size() != policies.getForRic(ric.ric.id()).size()) {
                 return startSynchronization(ric);
             }
 
index 1eefeee..d8cd04e 100644 (file)
@@ -43,12 +43,12 @@ import reactor.core.publisher.Mono;
 import reactor.core.publisher.SignalType;
 
 /**
- * Synchronizes the content of a RIC with the content in the repository. This
- * means:
+ * Synchronizes the content of a NearRT-RIC with the content in the repository.
+ * This means:
  * <p>
  * load all policy types
  * <p>
- * send all policy instances to the RIC
+ * send all policy instances to the NearRT-RIC
  * <p>
  * if that fails remove all policy instances
  * <p>
@@ -74,10 +74,10 @@ public class RicSynchronizationTask {
     }
 
     public void run(Ric ric) {
-        logger.debug("Handling ric: {}", ric.getConfig().name());
+        logger.debug("Handling ric: {}", ric.getConfig().ricId());
 
         if (ric.getState() == RicState.SYNCHRONIZING) {
-            logger.debug("Ric: {} is already being synchronized", ric.getConfig().name());
+            logger.debug("Ric: {} is already being synchronized", ric.getConfig().ricId());
             return;
         }
 
@@ -89,7 +89,7 @@ public class RicSynchronizationTask {
             .subscribe(new BaseSubscriber<Object>() {
                 @Override
                 protected void hookOnError(Throwable throwable) {
-                    logger.warn("Synchronization failure for ric: {}, reason: {}", ric.name(), throwable.getMessage());
+                    logger.warn("Synchronization failure for ric: {}, reason: {}", ric.id(), throwable.getMessage());
                     ric.setState(RicState.UNAVAILABLE);
                 }
 
@@ -109,7 +109,7 @@ public class RicSynchronizationTask {
     private Mono<Ric> setRicState(Ric ric) {
         synchronized (ric) {
             if (ric.getState() == RicState.SYNCHRONIZING) {
-                logger.debug("Ric: {} is already being synchronized", ric.getConfig().name());
+                logger.debug("Ric: {} is already being synchronized", ric.getConfig().ricId());
                 return Mono.empty();
             }
             ric.setState(RicState.SYNCHRONIZING);
@@ -126,9 +126,9 @@ public class RicSynchronizationTask {
     }
 
     private void onSynchronizationComplete(Ric ric) {
-        logger.debug("Synchronization completed for: {}", ric.name());
+        logger.debug("Synchronization completed for: {}", ric.id());
         ric.setState(RicState.AVAILABLE);
-        notifyAllServices("Synchronization completed for:" + ric.name());
+        notifyAllServices("Synchronization completed for:" + ric.id());
     }
 
     private void notifyAllServices(String body) {
@@ -147,7 +147,7 @@ public class RicSynchronizationTask {
     }
 
     private Flux<Object> deleteAllPolicyInstances(Ric ric, Throwable t) {
-        logger.debug("Recreation of policies failed for ric: {}, reason: {}", ric.name(), t.getMessage());
+        logger.debug("Recreation of policies failed for ric: {}, reason: {}", ric.id(), t.getMessage());
         deleteAllPoliciesInRepository(ric);
 
         Flux<PolicyType> synchronizedTypes = this.a1ClientFactory.createA1Client(ric) //
@@ -167,7 +167,7 @@ public class RicSynchronizationTask {
         return a1Client.getPolicyTypeIdentities() //
             .doOnNext(x -> ric.clearSupportedPolicyTypes()) //
             .flatMapMany(Flux::fromIterable) //
-            .doOnNext(typeId -> logger.debug("For ric: {}, handling type: {}", ric.getConfig().name(), typeId)) //
+            .doOnNext(typeId -> logger.debug("For ric: {}, handling type: {}", ric.getConfig().ricId(), typeId)) //
             .flatMap(policyTypeId -> getPolicyType(policyTypeId, a1Client), CONCURRENCY_RIC) //
             .doOnNext(ric::addSupportedPolicyType); //
     }
@@ -181,19 +181,19 @@ public class RicSynchronizationTask {
     }
 
     private Mono<PolicyType> createPolicyType(String policyTypeId, String schema) {
-        PolicyType pt = ImmutablePolicyType.builder().name(policyTypeId).schema(schema).build();
+        PolicyType pt = ImmutablePolicyType.builder().id(policyTypeId).schema(schema).build();
         policyTypes.put(pt);
         return Mono.just(pt);
     }
 
     private void deleteAllPoliciesInRepository(Ric ric) {
-        for (Policy policy : policies.getForRic(ric.name())) {
+        for (Policy policy : policies.getForRic(ric.id())) {
             this.policies.remove(policy);
         }
     }
 
     private Flux<Policy> putPolicy(Policy policy, Ric ric, A1Client a1Client) {
-        logger.debug("Recreating policy: {}, for ric: {}", policy.id(), ric.getConfig().name());
+        logger.debug("Recreating policy: {}, for ric: {}", policy.id(), ric.getConfig().ricId());
         return a1Client.putPolicy(policy) //
             .flatMapMany(notUsed -> Flux.just(policy));
     }
@@ -206,7 +206,7 @@ public class RicSynchronizationTask {
     }
 
     private Flux<Policy> recreateAllPoliciesInRic(Ric ric, A1Client a1Client) {
-        return Flux.fromIterable(policies.getForRic(ric.name())) //
+        return Flux.fromIterable(policies.getForRic(ric.id())) //
             .filter(policy -> !checkTransient(policy)) //
             .flatMap(policy -> putPolicy(policy, ric, a1Client), CONCURRENCY_RIC);
     }
index c066e12..a46ff1f 100644 (file)
@@ -96,7 +96,7 @@ public class ServiceSupervision {
             .doOnNext(notUsed -> policies.remove(policy)) //
             .flatMap(notUsed -> deletePolicyInRic(policy))
             .doOnNext(notUsed -> logger.debug("Policy deleted due to service inactivity: {}, service: {}", policy.id(),
-                policy.ownerServiceName())) //
+                policy.ownerServiceId())) //
             .doOnNext(notUsed -> lock.unlockBlocking()) //
             .doOnError(throwable -> lock.unlockBlocking()) //
             .doOnError(throwable -> logger.debug("Failed to delete inactive policy: {}, reason: {}", policy.id(),
@@ -117,7 +117,7 @@ public class ServiceSupervision {
     }
 
     private Mono<String> handleDeleteFromRicFailure(Policy policy, Throwable e) {
-        logger.warn("Could not delete policy: {} from ric: {}. Cause: {}", policy.id(), policy.ric().name(),
+        logger.warn("Could not delete policy: {} from ric: {}. Cause: {}", policy.id(), policy.ric().id(),
             e.getMessage());
         return Mono.empty();
     }
@@ -49,9 +49,9 @@ import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicC
 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.PolicyInfo;
-import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceRegistrationInfo;
-import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceStatus;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1.PolicyInfo;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1.ServiceRegistrationInfo;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v1.ServiceStatus;
 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
 import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
@@ -95,8 +95,8 @@ import reactor.util.annotation.Nullable;
     properties = { //
         "server.ssl.key-store=./config/keystore.jks", //
         "app.webclient.trust-store=./config/truststore.jks"})
-class ApplicationTest {
-    private static final Logger logger = LoggerFactory.getLogger(ApplicationTest.class);
+class ApplicationTestV1 {
+    private static final Logger logger = LoggerFactory.getLogger(ApplicationTestV1.class);
 
     @Autowired
     ApplicationContext context;
@@ -266,7 +266,8 @@ class ApplicationTest {
         Policy ricPolicy = ricPolicies.get(policyId);
         assertThat(ricPolicy.json()).isEqualTo(policy.json());
 
-        // Both types should be in the Policy Management Service's storage after the synch
+        // Both types should be in the Policy Management Service's storage after the
+        // synch
         assertThat(ric1.getSupportedPolicyTypes()).hasSize(2);
         assertThat(ric2.getSupportedPolicyTypes()).hasSize(2);
     }
@@ -325,8 +326,8 @@ class ApplicationTest {
         Policy policy = policies.getPolicy(policyInstanceId);
         assertThat(policy).isNotNull();
         assertThat(policy.id()).isEqualTo(policyInstanceId);
-        assertThat(policy.ownerServiceName()).isEqualTo(serviceName);
-        assertThat(policy.ric().name()).isEqualTo("ric1");
+        assertThat(policy.ownerServiceId()).isEqualTo(serviceName);
+        assertThat(policy.ric().id()).isEqualTo("ric1");
         assertThat(policy.isTransient()).isTrue();
 
         // Put a non transient policy
@@ -359,7 +360,8 @@ class ApplicationTest {
 
     @Test
     /**
-     * Test that HttpStatus and body from failing REST call to A1 is passed on to the caller.
+     * Test that HttpStatus and body from failing REST call to A1 is passed on to
+     * the caller.
      *
      * @throws ServiceException
      */
@@ -666,10 +668,10 @@ class ApplicationTest {
         Policy policy = ImmutablePolicy.builder() //
             .id(id) //
             .json(jsonString()) //
-            .ownerServiceName(service) //
+            .ownerServiceId(service) //
             .ric(rics.getRic(ric)) //
             .type(addPolicyType(typeName, ric)) //
-            .lastModified("lastModified") //
+            .lastModified(Instant.now()) //
             .isTransient(false) //
             .build();
         policies.put(policy);
@@ -712,29 +714,6 @@ class ApplicationTest {
         return "{\"servingCellNrcgi\":\"1\"}";
     }
 
-    @Test
-    void testConcurrency() throws Exception {
-        final Instant startTime = Instant.now();
-        List<Thread> threads = new ArrayList<>();
-        a1ClientFactory.setResponseDelay(Duration.ofMillis(1));
-        addRic("ric");
-        addPolicyType("type1", "ric");
-        addPolicyType("type2", "ric");
-
-        for (int i = 0; i < 10; ++i) {
-            Thread thread =
-                new Thread(new ConcurrencyTestRunnable(baseUrl(), supervision, a1ClientFactory, rics, policyTypes),
-                    "TestThread_" + i);
-            thread.start();
-            threads.add(thread);
-        }
-        for (Thread t : threads) {
-            t.join();
-        }
-        assertThat(policies.size()).isZero();
-        logger.info("Concurrency test took " + Duration.between(startTime, Instant.now()));
-    }
-
     private AsyncRestClient restClient(boolean useTrustValidation) {
         WebClientConfig config = this.applicationConfig.getWebClientConfig();
         config = ImmutableWebClientConfig.builder() //
@@ -779,7 +758,7 @@ class ApplicationTest {
 
     private PolicyType createPolicyType(String policyTypeName) {
         return ImmutablePolicyType.builder() //
-            .name(policyTypeName) //
+            .id(policyTypeName) //
             .schema("{\"title\":\"" + policyTypeName + "\"}") //
             .build();
     }
@@ -804,7 +783,7 @@ class ApplicationTest {
             mes.add(managedElement);
         }
         RicConfig conf = ImmutableRicConfig.builder() //
-            .name(ricName) //
+            .ricId(ricName) //
             .baseUrl(ricName) //
             .managedElementIds(mes) //
             .controllerName("") //
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTestV2.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTestV2.java
new file mode 100644 (file)
index 0000000..bc47baf
--- /dev/null
@@ -0,0 +1,874 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+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.v2.Consts;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.PolicyIdList;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.PolicyInfo;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.PolicyInfoList;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.PolicySchemaList;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.PolicyTypeIdList;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.RicInfo;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.ServiceRegistrationInfo;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.ServiceStatus;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.ServiceStatusList;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+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.onap.ccsdk.oran.a1policymanagementservice.tasks.RicSupervision;
+import org.onap.ccsdk.oran.a1policymanagementservice.tasks.ServiceSupervision;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1Client;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1ClientFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+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=./config/keystore.jks", //
+        "app.webclient.trust-store=./config/truststore.jks"})
+class ApplicationTestV2 {
+    private static final Logger logger = LoggerFactory.getLogger(ApplicationTestV2.class);
+
+    @Autowired
+    ApplicationContext context;
+
+    @Autowired
+    private Rics rics;
+
+    @Autowired
+    private Policies policies;
+
+    @Autowired
+    private PolicyTypes policyTypes;
+
+    @Autowired
+    MockA1ClientFactory a1ClientFactory;
+
+    @Autowired
+    RicSupervision supervision;
+
+    @Autowired
+    ApplicationConfig applicationConfig;
+
+    @Autowired
+    Services services;
+
+    private static Gson gson = new GsonBuilder() //
+        .serializeNulls() //
+        .create(); //
+
+    public static class MockApplicationConfig extends ApplicationConfig {
+        @Override
+        public String getLocalConfigurationFilePath() {
+            return ""; // No config file loaded for the test
+        }
+    }
+
+    /**
+     * Overrides the BeanFactory.
+     */
+    @TestConfiguration
+    static class TestBeanFactory {
+        private final PolicyTypes policyTypes = new PolicyTypes();
+        private final Services services = new Services();
+        private final Policies policies = new Policies();
+        MockA1ClientFactory a1ClientFactory = null;
+
+        @Bean
+        public ApplicationConfig getApplicationConfig() {
+            return new MockApplicationConfig();
+        }
+
+        @Bean
+        MockA1ClientFactory getA1ClientFactory() {
+            if (a1ClientFactory == null) {
+                this.a1ClientFactory = new MockA1ClientFactory(this.policyTypes);
+            }
+            return this.a1ClientFactory;
+        }
+
+        @Bean
+        public PolicyTypes getPolicyTypes() {
+            return this.policyTypes;
+        }
+
+        @Bean
+        Policies getPolicies() {
+            return this.policies;
+        }
+
+        @Bean
+        Services getServices() {
+            return this.services;
+        }
+
+        @Bean
+        public ServiceSupervision getServiceSupervision() {
+            Duration checkInterval = Duration.ofMillis(1);
+            return new ServiceSupervision(this.services, this.policies, this.getA1ClientFactory(), checkInterval);
+        }
+
+        @Bean
+        public ServletWebServerFactory servletContainer() {
+            return new TomcatServletWebServerFactory();
+        }
+
+    }
+
+    @LocalServerPort
+    private int port;
+
+    @BeforeEach
+    void reset() {
+        rics.clear();
+        policies.clear();
+        policyTypes.clear();
+        services.clear();
+        a1ClientFactory.reset();
+    }
+
+    @AfterEach
+    void verifyNoRicLocks() {
+        for (Ric ric : this.rics.getRics()) {
+            ric.getLock().lockBlocking(LockType.EXCLUSIVE);
+            ric.getLock().unlockBlocking();
+            assertThat(ric.getLock().getLockCounter()).isZero();
+            assertThat(ric.getState()).isEqualTo(Ric.RicState.AVAILABLE);
+        }
+    }
+
+    @Test
+    void testGetRics() throws Exception {
+        addRic("ric1");
+        this.addPolicyType("type1", "ric1");
+        String url = "/rics?policytype_id=type1";
+        String rsp = restClient().get(url).block();
+        assertThat(rsp).contains("ric1");
+
+        // nameless type for ORAN A1 1.1
+        addRic("ric2");
+        this.addPolicyType("", "ric2");
+        url = "/rics?policytype_id=";
+
+        // This tests also validation of trusted certs restClient(true)
+        rsp = restClient(true).get(url).block();
+        assertThat(rsp).contains("ric2") //
+            .doesNotContain("ric1") //
+            .contains("AVAILABLE");
+
+        // All RICs
+        rsp = restClient().get("/rics").block();
+        assertThat(rsp).contains("ric2") //
+            .contains("ric1");
+
+        // Non existing policy type
+        url = "/rics?policytype_id=XXXX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+    }
+
+    @Test
+    void testSynchronization() throws Exception {
+        // Two polictypes will be put in the NearRT RICs
+        PolicyTypes nearRtRicPolicyTypes = new PolicyTypes();
+        nearRtRicPolicyTypes.put(createPolicyType("typeName"));
+        nearRtRicPolicyTypes.put(createPolicyType("typeName2"));
+        this.a1ClientFactory.setPolicyTypes(nearRtRicPolicyTypes);
+
+        // One type and one instance added to the Policy Management Service's storage
+        final String ric1Name = "ric1";
+        Ric ric1 = addRic(ric1Name);
+        Policy policy2 = addPolicy("policyId2", "typeName", "service", ric1Name);
+        Ric ric2 = addRic("ric2");
+
+        getA1Client(ric1Name).putPolicy(policy2); // put it in the RIC (NearRT-RIC)
+        policies.remove(policy2); // Remove it from the repo -> should be deleted in the RIC
+
+        String policyId = "policyId";
+        Policy policy = addPolicy(policyId, "typeName", "service", ric1Name); // This should be created in the RIC
+        supervision.checkAllRics(); // The created policy should be put in the RIC
+
+        // Wait until synch is completed
+        await().untilAsserted(() -> RicState.SYNCHRONIZING.equals(rics.getRic(ric1Name).getState()));
+        await().untilAsserted(() -> RicState.AVAILABLE.equals(rics.getRic(ric1Name).getState()));
+        await().untilAsserted(() -> RicState.AVAILABLE.equals(rics.getRic("ric2").getState()));
+
+        Policies ricPolicies = getA1Client(ric1Name).getPolicies();
+        assertThat(ricPolicies.size()).isEqualTo(1);
+        Policy ricPolicy = ricPolicies.get(policyId);
+        assertThat(ricPolicy.json()).isEqualTo(policy.json());
+
+        // Both types should be in the Policy Management Service's storage after the
+        // synch
+        assertThat(ric1.getSupportedPolicyTypes()).hasSize(2);
+        assertThat(ric2.getSupportedPolicyTypes()).hasSize(2);
+    }
+
+    @Test
+    void testGetRic() throws Exception {
+        String ricId = "ric1";
+        String managedElementId = "kista_1";
+        addRic(ricId, managedElementId);
+
+        String url = "/ric?managed_element_id=" + managedElementId;
+        String rsp = restClient().get(url).block();
+        RicInfo ricInfo = gson.fromJson(rsp, RicInfo.class);
+        assertThat(ricInfo.ricId).isEqualTo(ricId);
+
+        url = "/ric?ric_id=" + ricId;
+        rsp = restClient().get(url).block();
+        ricInfo = gson.fromJson(rsp, RicInfo.class);
+        assertThat(ricInfo.ricId).isEqualTo(ricId);
+
+        // test GET RIC for ManagedElement that does not exist
+        url = "/ric?managed_element_id=" + "junk";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+
+        url = "/ric";
+        testErrorCode(restClient().get(url), HttpStatus.BAD_REQUEST);
+    }
+
+    private String putPolicyUrl(String serviceName, String ricId, String policyTypeName, String policyInstanceId,
+        boolean isTransient) {
+        String url;
+        if (policyTypeName.isEmpty()) {
+            url = "/policy?policy_id=" + policyInstanceId + "&ric_id=" + ricId + "&service_id=" + serviceName;
+        } else {
+            url = "/policy?policy_id=" + policyInstanceId + "&ric_id=" + ricId + "&service_id=" + serviceName
+                + "&policytype_id=" + policyTypeName;
+        }
+        if (isTransient) {
+            url += "&transient=true";
+        }
+        return url;
+    }
+
+    private String putPolicyUrl(String serviceName, String ricId, String policyTypeName, String policyInstanceId) {
+        return putPolicyUrl(serviceName, ricId, policyTypeName, policyInstanceId, false);
+    }
+
+    @Test
+    void testPutPolicy() throws Exception {
+        String serviceName = "service1";
+        String ricId = "ric1";
+        String policyTypeName = "type1";
+        String policyInstanceId = "instance1";
+
+        putService(serviceName);
+        addPolicyType(policyTypeName, ricId);
+
+        // PUT a transient policy
+        String url = putPolicyUrl(serviceName, ricId, policyTypeName, policyInstanceId, true);
+        final String policyBody = jsonString();
+        this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE);
+
+        restClient().put(url, policyBody).block();
+
+        Policy policy = policies.getPolicy(policyInstanceId);
+        assertThat(policy).isNotNull();
+        assertThat(policy.id()).isEqualTo(policyInstanceId);
+        assertThat(policy.ownerServiceId()).isEqualTo(serviceName);
+        assertThat(policy.ric().id()).isEqualTo("ric1");
+        assertThat(policy.isTransient()).isTrue();
+
+        // Put a non transient policy
+        url = putPolicyUrl(serviceName, ricId, policyTypeName, policyInstanceId);
+        restClient().put(url, policyBody).block();
+        policy = policies.getPolicy(policyInstanceId);
+        assertThat(policy.isTransient()).isFalse();
+
+        url = "/policies";
+        String rsp = restClient().get(url).block();
+        assertThat(rsp).as("Response contains policy instance ID.").contains(policyInstanceId);
+
+        url = "/policy?policy_id=" + policyInstanceId;
+        rsp = restClient().get(url).block();
+        assertThat(rsp).isEqualTo(policyBody);
+
+        // Test of error codes
+        url = putPolicyUrl(serviceName, ricId + "XX", policyTypeName, policyInstanceId);
+        testErrorCode(restClient().put(url, policyBody), HttpStatus.NOT_FOUND);
+
+        url = putPolicyUrl(serviceName, ricId, policyTypeName + "XX", policyInstanceId);
+        addPolicyType(policyTypeName + "XX", "otherRic");
+        testErrorCode(restClient().put(url, policyBody), HttpStatus.NOT_FOUND);
+
+        url = putPolicyUrl(serviceName, ricId, policyTypeName, policyInstanceId);
+        this.rics.getRic(ricId).setState(Ric.RicState.SYNCHRONIZING);
+        testErrorCode(restClient().put(url, policyBody), HttpStatus.LOCKED);
+        this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE);
+    }
+
+    @Test
+    /**
+     * Test that HttpStatus and body from failing REST call to A1 is passed on to
+     * the caller.
+     *
+     * @throws ServiceException
+     */
+    void testErrorFromRic() throws ServiceException {
+        putService("service1");
+        addPolicyType("type1", "ric1");
+
+        String url = putPolicyUrl("service1", "ric1", "type1", "id1");
+        MockA1Client a1Client = a1ClientFactory.getOrCreateA1Client("ric1");
+        HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
+        String responseBody = "Refused";
+        byte[] responseBodyBytes = responseBody.getBytes(StandardCharsets.UTF_8);
+
+        WebClientResponseException a1Exception = new WebClientResponseException(httpStatus.value(), "statusText", null,
+            responseBodyBytes, StandardCharsets.UTF_8, null);
+        doReturn(Mono.error(a1Exception)).when(a1Client).putPolicy(any());
+
+        // PUT Policy
+        testErrorCode(restClient().put(url, "{}"), httpStatus, responseBody);
+
+        // DELETE POLICY
+        this.addPolicy("instance1", "type1", "service1", "ric1");
+        doReturn(Mono.error(a1Exception)).when(a1Client).deletePolicy(any());
+        testErrorCode(restClient().delete("/policy?policy_id=instance1"), httpStatus, responseBody);
+
+        // GET STATUS
+        this.addPolicy("instance1", "type1", "service1", "ric1");
+        doReturn(Mono.error(a1Exception)).when(a1Client).getPolicyStatus(any());
+        testErrorCode(restClient().get("/policy-status?policy_id=instance1"), httpStatus, responseBody);
+
+        // Check that empty response body is OK
+        a1Exception = new WebClientResponseException(httpStatus.value(), "", null, null, null, null);
+        doReturn(Mono.error(a1Exception)).when(a1Client).getPolicyStatus(any());
+        testErrorCode(restClient().get("/policy-status?policy_id=instance1"), httpStatus);
+    }
+
+    @Test
+    void testPutTypelessPolicy() throws Exception {
+        putService("service1");
+        addPolicyType("", "ric1");
+        String url = putPolicyUrl("service1", "ric1", "", "id1");
+        restClient().put(url, jsonString()).block();
+
+        String rsp = restClient().get("/policies").block();
+        PolicyInfoList info = gson.fromJson(rsp, PolicyInfoList.class);
+        assertThat(info.policies).hasSize(1);
+        PolicyInfo policyInfo = info.policies.iterator().next();
+        assertThat(policyInfo.policyId).isEqualTo("id1");
+        assertThat(policyInfo.policyTypeId).isEmpty();
+    }
+
+    @Test
+    void testRefuseToUpdatePolicy() throws Exception {
+        // Test that only the json can be changed for a already created policy
+        // In this case service is attempted to be changed
+        this.addRic("ric1");
+        this.addRic("ricXXX");
+        this.addPolicy("instance1", "type1", "service1", "ric1");
+        this.addPolicy("instance2", "type1", "service1", "ricXXX");
+
+        // Try change ric1 -> ricXXX
+        String urlWrongRic = putPolicyUrl("service1", "ricXXX", "type1", "instance1");
+        testErrorCode(restClient().put(urlWrongRic, jsonString()), HttpStatus.CONFLICT);
+    }
+
+    @Test
+    void testGetPolicy() throws Exception {
+        String url = "/policy?policy_id=id";
+        Policy policy = addPolicy("id", "typeName", "service1", "ric1");
+        {
+            String rsp = restClient().get(url).block();
+            assertThat(rsp).isEqualTo(policy.json());
+        }
+        {
+            policies.remove(policy);
+            testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+        }
+    }
+
+    @Test
+    void testDeletePolicy() throws Exception {
+        addPolicy("id", "typeName", "service1", "ric1");
+        assertThat(policies.size()).isEqualTo(1);
+
+        String url = "/policy?policy_id=id";
+        ResponseEntity<String> entity = restClient().deleteForEntity(url).block();
+
+        assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
+        assertThat(policies.size()).isZero();
+
+        // Delete a non existing policy
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+    }
+
+    @Test
+    void testGetPolicySchemas() throws Exception {
+        addPolicyType("type1", "ric1");
+        addPolicyType("type2", "ric2");
+
+        String url = "/policy-schemas";
+        String rsp = this.restClient().get(url).block();
+        assertThat(rsp).contains("type1") //
+            .contains("[{\"title\":\"type2\"}");
+
+        PolicySchemaList info = parseSchemas(rsp);
+        assertThat(info.schemas).hasSize(2);
+
+        url = "/policy-schemas?ric_id=ric1";
+        rsp = restClient().get(url).block();
+        assertThat(rsp).contains("type1");
+        info = parseSchemas(rsp);
+        assertThat(info.schemas).hasSize(1);
+
+        // Schema for type
+        url = "/policy-schemas?policytype_id=type1";
+        rsp = restClient().get(url).block();
+        assertThat(rsp).contains("type1") //
+            .contains("title");
+
+        // Both type and ric specified
+        url = "/policy-schemas?ric_id=ric1&policytype_id=type1";
+        rsp = restClient().get(url).block();
+        PolicySchemaList list = gson.fromJson(rsp, PolicySchemaList.class);
+        assertThat(list.schemas.size()).isEqualTo(1);
+
+        url = "/policy-schemas?ric_id=ric1&policytype_id=type2";
+        rsp = restClient().get(url).block();
+        list = gson.fromJson(rsp, PolicySchemaList.class);
+        assertThat(list.schemas.size()).isEqualTo(0);
+
+        // Get schema for non existing RIC
+        url = "/policy-schemas?ric_id=ric1XXX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+
+        // Get non existing schema
+        url = "/policy-schemas?policytype_id=type1XX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+    }
+
+    String createPolicyTypesJson(String... types) {
+        List<String> list = new ArrayList<>();
+        Collections.addAll(list, types);
+        PolicyTypeIdList ids = new PolicyTypeIdList(list);
+        return gson.toJson(ids);
+    }
+
+    @Test
+    void testGetPolicyTypes() throws Exception {
+        addPolicyType("type1", "ric1");
+        addPolicyType("type2", "ric2");
+
+        String url = "/policy-types";
+        String rsp = restClient().get(url).block();
+        String expResp = createPolicyTypesJson("type2", "type1");
+        assertThat(rsp).isEqualTo(expResp);
+
+        url = "/policy-types?ric_id=ric1";
+        rsp = restClient().get(url).block();
+        expResp = createPolicyTypesJson("type1");
+        assertThat(rsp).isEqualTo(expResp);
+
+        // Get policy types for non existing RIC
+        url = "/policy-types?ric_id=ric1XXX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+    }
+
+    @Test
+    void testGetPolicies() throws Exception {
+        addPolicy("id1", "type1", "service1");
+
+        String url = "/policies";
+        String rsp = restClient().get(url).block();
+        logger.info(rsp);
+        PolicyInfoList info = gson.fromJson(rsp, PolicyInfoList.class);
+        assertThat(info.policies).hasSize(1);
+        PolicyInfo policyInfo = info.policies.iterator().next();
+        assert (policyInfo.validate());
+        assertThat(policyInfo.policyId).isEqualTo("id1");
+        assertThat(policyInfo.policyTypeId).isEqualTo("type1");
+        assertThat(policyInfo.serviceId).isEqualTo("service1");
+    }
+
+    @Test
+    void testGetPoliciesFilter() throws Exception {
+        addPolicy("id1", "type1", "service1");
+        addPolicy("id2", "type1", "service2");
+        addPolicy("id3", "type2", "service1");
+
+        String url = "/policies?policytype_id=type1";
+        String rsp = restClient().get(url).block();
+        logger.info(rsp);
+        assertThat(rsp).contains("id1") //
+            .contains("id2") //
+            .doesNotContain("id3");
+
+        url = "/policies?policytype_id=type1&service_id=service2";
+        rsp = restClient().get(url).block();
+        logger.info(rsp);
+        assertThat(rsp).doesNotContain("id1") //
+            .contains("id2") //
+            .doesNotContain("id3");
+
+        // Test get policies for non existing type
+        url = "/policies?policytype_id=type1XXX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+
+        // Test get policies for non existing RIC
+        url = "/policies?ric_id=XXX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+    }
+
+    @Test
+    void testGetPolicyIdsFilter() throws Exception {
+        addPolicy("id1", "type1", "service1", "ric1");
+        addPolicy("id2", "type1", "service2", "ric1");
+        addPolicy("id3", "type2", "service1", "ric1");
+
+        String url = "/policy-ids?policytype_id=type1";
+        String rsp = restClient().get(url).block();
+        logger.info(rsp);
+        assertThat(rsp).contains("id1") //
+            .contains("id2") //
+            .doesNotContain("id3");
+
+        url = "/policy-ids?policytype_id=type1&service_id=service1&ric=ric1";
+        rsp = restClient().get(url).block();
+        PolicyIdList respList = gson.fromJson(rsp, PolicyIdList.class);
+        assertThat(respList.policyIds.iterator().next()).isEqualTo("id1");
+
+        // Test get policy ids for non existing type
+        url = "/policy-ids?policytype_id=type1XXX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+
+        // Test get policy ids for non existing RIC
+        url = "/policy-ids?ric_id=XXX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+    }
+
+    @Test
+    void testPutAndGetService() throws Exception {
+        // PUT
+        String serviceName = "name";
+        putService(serviceName, 0, HttpStatus.CREATED);
+        putService(serviceName, 0, HttpStatus.OK);
+
+        // GET one service
+        String url = "/services?service_id=name";
+        String rsp = restClient().get(url).block();
+        ServiceStatusList info = gson.fromJson(rsp, ServiceStatusList.class);
+        assertThat(info.statusList).hasSize(1);
+        ServiceStatus status = info.statusList.iterator().next();
+        assertThat(status.keepAliveIntervalSeconds).isZero();
+        assertThat(status.serviceId).isEqualTo(serviceName);
+
+        // GET (all)
+        url = "/services";
+        rsp = restClient().get(url).block();
+        assertThat(rsp).as("Response contains service name").contains(serviceName);
+        logger.info(rsp);
+
+        // Keep alive
+        url = "/services/keepalive?service_id=name";
+        ResponseEntity<?> entity = restClient().putForEntity(url).block();
+        assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
+
+        // DELETE service
+        assertThat(services.size()).isEqualTo(1);
+        url = "/services?service_id=name";
+        restClient().delete(url).block();
+        assertThat(services.size()).isZero();
+
+        // Keep alive, no registered service
+        testErrorCode(restClient().put("/services/keepalive?service_id=name", ""), HttpStatus.NOT_FOUND);
+
+        // PUT service with bad payload
+        testErrorCode(restClient().put("/services", "crap"), HttpStatus.BAD_REQUEST, false);
+        testErrorCode(restClient().put("/services", "{}"), HttpStatus.BAD_REQUEST, false);
+        testErrorCode(restClient().put("/services", createServiceJson(serviceName, -123)), HttpStatus.BAD_REQUEST,
+            false);
+        testErrorCode(restClient().put("/services", createServiceJson(serviceName, 0, "missing.portandprotocol.com")),
+            HttpStatus.BAD_REQUEST, false);
+
+        // GET non existing service
+        testErrorCode(restClient().get("/services?service_id=XXX"), HttpStatus.NOT_FOUND);
+    }
+
+    @Test
+    void testServiceSupervision() throws Exception {
+        putService("service1", 1, HttpStatus.CREATED);
+        addPolicyType("type1", "ric1");
+
+        String url = putPolicyUrl("service1", "ric1", "type1", "instance1");
+        final String policyBody = jsonString();
+        restClient().put(url, policyBody).block();
+
+        assertThat(policies.size()).isEqualTo(1);
+        assertThat(services.size()).isEqualTo(1);
+
+        // Timeout after ~1 second
+        await().untilAsserted(() -> assertThat(policies.size()).isZero());
+        assertThat(services.size()).isZero();
+    }
+
+    @Test
+    void testGetPolicyStatus() throws Exception {
+        addPolicy("id", "typeName", "service1", "ric1");
+        assertThat(policies.size()).isEqualTo(1);
+
+        String url = "/policy-status?policy_id=id";
+        String rsp = restClient().get(url).block();
+        assertThat(rsp).isEqualTo("OK");
+
+        // GET non existing policy status
+        url = "/policy-status?policy_id=XXX";
+        testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+    }
+
+    private Policy addPolicy(String id, String typeName, String service, String ric) throws ServiceException {
+        addRic(ric);
+        Policy policy = ImmutablePolicy.builder() //
+            .id(id) //
+            .json(jsonString()) //
+            .ownerServiceId(service) //
+            .ric(rics.getRic(ric)) //
+            .type(addPolicyType(typeName, ric)) //
+            .lastModified(Instant.now()) //
+            .isTransient(false) //
+            .build();
+        policies.put(policy);
+        return policy;
+    }
+
+    private Policy addPolicy(String id, String typeName, String service) throws ServiceException {
+        return addPolicy(id, typeName, service, "ric");
+    }
+
+    private String createServiceJson(String name, long keepAliveIntervalSeconds) {
+        return createServiceJson(name, keepAliveIntervalSeconds, "https://examples.javacodegeeks.com/core-java/");
+    }
+
+    private String createServiceJson(String name, long keepAliveIntervalSeconds, String url) {
+        ServiceRegistrationInfo service = new ServiceRegistrationInfo(name, keepAliveIntervalSeconds, url);
+
+        String json = gson.toJson(service);
+        return json;
+    }
+
+    private void putService(String name) {
+        putService(name, 0, null);
+    }
+
+    private void putService(String name, long keepAliveIntervalSeconds, @Nullable HttpStatus expectedStatus) {
+        String url = "/services";
+        String body = createServiceJson(name, keepAliveIntervalSeconds);
+        ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
+        if (expectedStatus != null) {
+            assertEquals(expectedStatus, resp.getStatusCode(), "");
+        }
+    }
+
+    private String baseUrl() {
+        return "https://localhost:" + port + Consts.V2_API_ROOT;
+    }
+
+    private String jsonString() {
+        return "{\"servingCellNrcgi\":\"1\"}";
+    }
+
+    @Test
+    void testConcurrency() throws Exception {
+        final Instant startTime = Instant.now();
+        List<Thread> threads = new ArrayList<>();
+        List<ConcurrencyTestRunnable> tests = new ArrayList<>();
+        a1ClientFactory.setResponseDelay(Duration.ofMillis(1));
+        addRic("ric");
+        addPolicyType("type1", "ric");
+        addPolicyType("type2", "ric");
+
+        for (int i = 0; i < 10; ++i) {
+            AsyncRestClient restClient = restClient();
+            ConcurrencyTestRunnable test =
+                new ConcurrencyTestRunnable(restClient, supervision, a1ClientFactory, rics, policyTypes);
+            Thread thread = new Thread(test, "TestThread_" + i);
+            thread.start();
+            threads.add(thread);
+            tests.add(test);
+        }
+        for (Thread t : threads) {
+            t.join();
+        }
+        for (ConcurrencyTestRunnable test : tests) {
+            assertThat(test.isFailed()).isFalse();
+        }
+        assertThat(policies.size()).isZero();
+        logger.info("Concurrency test took " + Duration.between(startTime, Instant.now()));
+    }
+
+    private AsyncRestClient restClient(boolean useTrustValidation) {
+        WebClientConfig config = this.applicationConfig.getWebClientConfig();
+        config = ImmutableWebClientConfig.builder() //
+            .keyStoreType(config.keyStoreType()) //
+            .keyStorePassword(config.keyStorePassword()) //
+            .keyStore(config.keyStore()) //
+            .keyPassword(config.keyPassword()) //
+            .isTrustStoreUsed(useTrustValidation) //
+            .trustStore(config.trustStore()) //
+            .trustStorePassword(config.trustStorePassword()) //
+            .build();
+
+        return new AsyncRestClient(baseUrl(), config);
+    }
+
+    private AsyncRestClient restClient() {
+        return restClient(false);
+    }
+
+    private void testErrorCode(Mono<?> request, HttpStatus expStatus) {
+        testErrorCode(request, expStatus, "", true);
+    }
+
+    private void testErrorCode(Mono<?> request, HttpStatus expStatus, boolean expectApplicationProblemJsonMediaType) {
+        testErrorCode(request, expStatus, "", expectApplicationProblemJsonMediaType);
+    }
+
+    private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains) {
+        testErrorCode(request, expStatus, responseContains, true);
+    }
+
+    private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains,
+        boolean expectApplicationProblemJsonMediaType) {
+        StepVerifier.create(request) //
+            .expectSubscription() //
+            .expectErrorMatches(
+                t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType)) //
+            .verify();
+    }
+
+    private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains,
+        boolean expectApplicationProblemJsonMediaType) {
+        assertTrue(throwable instanceof WebClientResponseException);
+        WebClientResponseException responseException = (WebClientResponseException) throwable;
+        assertThat(responseException.getStatusCode()).isEqualTo(expStatus);
+        assertThat(responseException.getResponseBodyAsString()).contains(responseContains);
+        if (expectApplicationProblemJsonMediaType) {
+            assertThat(responseException.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_PROBLEM_JSON);
+        }
+        return true;
+    }
+
+    private MockA1Client getA1Client(String ricId) throws ServiceException {
+        return a1ClientFactory.getOrCreateA1Client(ricId);
+    }
+
+    private PolicyType createPolicyType(String policyTypeName) {
+        return ImmutablePolicyType.builder() //
+            .id(policyTypeName) //
+            .schema("{\"title\":\"" + policyTypeName + "\"}") //
+            .build();
+    }
+
+    private PolicyType addPolicyType(String policyTypeName, String ricId) {
+        PolicyType type = createPolicyType(policyTypeName);
+        policyTypes.put(type);
+        addRic(ricId).addSupportedPolicyType(type);
+        return type;
+    }
+
+    private Ric addRic(String ricId) {
+        return addRic(ricId, null);
+    }
+
+    private Ric addRic(String ricId, String managedElement) {
+        if (rics.get(ricId) != null) {
+            return rics.get(ricId);
+        }
+        List<String> mes = new ArrayList<>();
+        if (managedElement != null) {
+            mes.add(managedElement);
+        }
+        RicConfig conf = ImmutableRicConfig.builder() //
+            .ricId(ricId) //
+            .baseUrl(ricId) //
+            .managedElementIds(mes) //
+            .controllerName("") //
+            .build();
+        Ric ric = new Ric(conf);
+        ric.setState(Ric.RicState.AVAILABLE);
+        this.rics.put(ric);
+        return ric;
+    }
+
+    private static PolicySchemaList parseSchemas(String jsonString) {
+        return gson.fromJson(jsonString, PolicySchemaList.class);
+    }
+}
index 7a882ad..0e8803a 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice;
 
+import java.time.Instant;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
@@ -49,15 +50,16 @@ class ConcurrencyTestRunnable implements Runnable {
     private final MockA1ClientFactory a1ClientFactory;
     private final Rics rics;
     private final PolicyTypes types;
+    private boolean failed = false;
 
-    ConcurrencyTestRunnable(String baseUrl, RicSupervision supervision, MockA1ClientFactory a1ClientFactory, Rics rics,
-        PolicyTypes types) {
+    ConcurrencyTestRunnable(AsyncRestClient client, RicSupervision supervision, MockA1ClientFactory a1ClientFactory,
+        Rics rics, PolicyTypes types) {
         this.count = nextCount.incrementAndGet();
         this.supervision = supervision;
         this.a1ClientFactory = a1ClientFactory;
         this.rics = rics;
         this.types = types;
-        this.webClient = new AsyncRestClient(baseUrl);
+        this.webClient = client;
     }
 
     private void printStatusInfo() {
@@ -94,9 +96,14 @@ class ConcurrencyTestRunnable implements Runnable {
         } catch (Exception e) {
             logger.error("Concurrency test exception " + e.toString());
             printStatusInfo();
+            failed = true;
         }
     }
 
+    public boolean isFailed() {
+        return this.failed;
+    }
+
     private Policy createPolicyObject(String id) {
         Ric ric = this.rics.get("ric");
         PolicyType type = this.types.get("type1");
@@ -105,8 +112,8 @@ class ConcurrencyTestRunnable implements Runnable {
             .json("{}") //
             .type(type) //
             .ric(ric) //
-            .ownerServiceName("") //
-            .lastModified("") //
+            .ownerServiceId("") //
+            .lastModified(Instant.now()) //
             .isTransient(false) //
             .build();
     }
@@ -124,17 +131,17 @@ class ConcurrencyTestRunnable implements Runnable {
     }
 
     private void listTypes() {
-        String uri = "/policy_types";
+        String uri = "/policy-types";
         webClient.getForEntity(uri).block();
     }
 
     private void putPolicy(String name) {
-        String putUrl = "/policy?type=type1&id=" + name + "&ric=ric&service=service1";
+        String putUrl = "/policy?policytype_id=type1&policy_id=" + name + "&ric_id=ric&service_id=service1";
         webClient.putForEntity(putUrl, "{}").block();
     }
 
     private void deletePolicy(String name) {
-        String deleteUrl = "/policy?id=" + name;
+        String deleteUrl = "/policy?policy_id=" + name;
         webClient.delete(deleteUrl).block();
     }
 }
index aa917cb..6ccf162 100644 (file)
@@ -29,6 +29,7 @@ import java.io.File;
 import java.io.IOException;
 import java.net.URL;
 import java.nio.file.Files;
+import java.time.Instant;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -134,13 +135,13 @@ class MockPolicyManagementService {
                 try {
                     String schema = readFile(file);
                     String typeName = title(schema);
-                    PolicyType type = ImmutablePolicyType.builder().name(typeName).schema(schema).build();
+                    PolicyType type = ImmutablePolicyType.builder().id(typeName).schema(schema).build();
                     policyTypes.put(type);
                 } catch (Exception e) {
                     logger.error("Could not load json schema ", e);
                 }
             }
-            policyTypes.put(ImmutablePolicyType.builder().name("").schema("{}").build());
+            policyTypes.put(ImmutablePolicyType.builder().id("").schema("{}").build());
         }
     }
 
@@ -187,10 +188,10 @@ class MockPolicyManagementService {
         Policy policy = ImmutablePolicy.builder() //
             .id("typelessPolicy") //
             .json(json) //
-            .ownerServiceName("MockPolicyManagementService") //
+            .ownerServiceId("MockPolicyManagementService") //
             .ric(ric) //
             .type(unnamedPolicyType) //
-            .lastModified("now") //
+            .lastModified(Instant.now()) //
             .isTransient(false) //
             .build();
         this.policies.put(policy);
index 86244e0..685c561 100644 (file)
@@ -70,7 +70,7 @@ class A1ClientFactoryTest {
 
     private static ImmutableRicConfig ricConfig(String controllerName) {
         return ImmutableRicConfig.builder() //
-            .name(RIC_NAME) //
+            .ricId(RIC_NAME) //
             .baseUrl("baseUrl") //
             .managedElementIds(new Vector<>()) //
             .controllerName(controllerName) //
@@ -118,7 +118,7 @@ class A1ClientFactoryTest {
             .expectError() //
             .verify();
 
-        assertEquals(A1ProtocolType.UNKNOWN, ric.getProtocolVersion(), "Protocol negotiation failed for " + ric.name());
+        assertEquals(A1ProtocolType.UNKNOWN, ric.getProtocolVersion(), "Protocol negotiation failed for " + ric.id());
     }
 
     private A1Client createClient(A1ProtocolType version) throws ServiceException {
index d096e0c..855a917 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.clients;
 
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Vector;
 
@@ -47,7 +48,7 @@ public class A1ClientHelper {
     }
 
     protected static Ric createRic(String url) {
-        RicConfig cfg = ImmutableRicConfig.builder().name("ric") //
+        RicConfig cfg = ImmutableRicConfig.builder().ricId("ric") //
             .baseUrl(url) //
             .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
             .controllerName("") //
@@ -59,16 +60,16 @@ public class A1ClientHelper {
         return ImmutablePolicy.builder() //
             .id(policyId) //
             .json(json) //
-            .ownerServiceName("service") //
+            .ownerServiceId("service") //
             .ric(createRic(nearRtRicUrl)) //
             .type(createPolicyType(type)) //
-            .lastModified("now") //
+            .lastModified(Instant.now()) //
             .isTransient(false) //
             .build();
     }
 
     protected static PolicyType createPolicyType(String name) {
-        return ImmutablePolicyType.builder().name(name).schema("schema").build();
+        return ImmutablePolicyType.builder().id(name).schema("schema").build();
     }
 
     protected static String getCreateSchema(String policyType, String policyTypeId) {
index fe6274c..d6d12ba 100644 (file)
@@ -67,7 +67,7 @@ class OscA1ClientTest {
     @BeforeEach
     void init() {
         RicConfig ricConfig = ImmutableRicConfig.builder() //
-            .name("name") //
+            .ricId("name") //
             .baseUrl("RicBaseUrl") //
             .managedElementIds(new ArrayList<>()) //
             .controllerName("") //
index 086af14..d0417a0 100644 (file)
@@ -144,7 +144,7 @@ class ApplicationConfigParserTest {
         JsonObject jsonRootObject = getJsonRootObject();
         JsonObject json = jsonRootObject.getAsJsonObject("config");
         json.remove("ric");
-        final String message = "Could not find member: 'ric' in: " + json;
+        final String message = "Could not find member: [ric] in: " + json;
 
         Exception actualException = assertThrows(ServiceException.class, () -> parserUnderTest.parse(jsonRootObject));
 
index f7bf2e8..eb2c147 100644 (file)
@@ -40,7 +40,7 @@ import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException
 class ApplicationConfigTest {
 
     private static final ImmutableRicConfig RIC_CONFIG_1 = ImmutableRicConfig.builder() //
-        .name("ric1") //
+        .ricId("ric1") //
         .baseUrl("ric1_url") //
         .managedElementIds(new Vector<>()) //
         .controllerName("") //
@@ -76,7 +76,7 @@ class ApplicationConfigTest {
         assertEquals(RicConfigUpdate.Type.ADDED, update.getType());
         assertTrue(appConfigUnderTest.getRicConfigs().contains(RIC_CONFIG_1), "Ric not added to configurations.");
 
-        assertEquals(RIC_CONFIG_1, appConfigUnderTest.getRic(RIC_CONFIG_1.name()),
+        assertEquals(RIC_CONFIG_1, appConfigUnderTest.getRic(RIC_CONFIG_1.ricId()),
             "Not correct Ric retrieved from configurations.");
 
         update = appConfigUnderTest.setConfiguration(configParserResult(RIC_CONFIG_1)).blockFirst();
@@ -92,7 +92,7 @@ class ApplicationConfigTest {
         appConfigUnderTest.setConfiguration(configParserResult(RIC_CONFIG_1));
 
         ImmutableRicConfig changedRicConfig = ImmutableRicConfig.builder() //
-            .name("ric1") //
+            .ricId("ric1") //
             .baseUrl("changed_ric1_url") //
             .managedElementIds(new Vector<>()) //
             .controllerName("") //
@@ -101,7 +101,7 @@ class ApplicationConfigTest {
         RicConfigUpdate update = appConfigUnderTest.setConfiguration(configParserResult(changedRicConfig)).blockFirst();
 
         assertEquals(RicConfigUpdate.Type.CHANGED, update.getType());
-        assertEquals(changedRicConfig, appConfigUnderTest.getRic(RIC_CONFIG_1.name()),
+        assertEquals(changedRicConfig, appConfigUnderTest.getRic(RIC_CONFIG_1.ricId()),
             "Changed Ric not retrieved from configurations.");
     }
 
@@ -110,7 +110,7 @@ class ApplicationConfigTest {
         ApplicationConfig appConfigUnderTest = new ApplicationConfig();
 
         ImmutableRicConfig ricConfig2 = ImmutableRicConfig.builder() //
-            .name("ric2") //
+            .ricId("ric2") //
             .baseUrl("ric2_url") //
             .managedElementIds(new Vector<>()) //
             .controllerName("") //
index dfa132d..2405e46 100644 (file)
@@ -48,8 +48,6 @@ import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentCaptor;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
 import org.onap.ccsdk.oran.a1policymanagementservice.dmaap.DmaapRequestMessage.Operation;
-import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
-import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
 import org.onap.ccsdk.oran.a1policymanagementservice.utils.LoggingUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -81,8 +79,7 @@ class DmaapMessageHandlerTest {
     }
 
     static String payloadAsString() {
-        PolicyType pt = ImmutablePolicyType.builder().name("name").schema("schema").build();
-        return gson.toJson(pt);
+        return "{\"param\":\"value\"}";
     }
 
     DmaapRequestMessage dmaapRequestMessage(Operation operation) {
@@ -277,7 +274,7 @@ class DmaapMessageHandlerTest {
     @Test
     void putWithoutPayload_thenNotFoundResponseWithWarning() throws Exception {
         String message = dmaapInputMessage(Operation.PUT).toString();
-        message = message.replace(",\"payload\":{\"name\":\"name\",\"schema\":\"schema\"}", "");
+        message = message.replace("payload", "junk");
 
         final ListAppender<ILoggingEvent> logAppender =
             LoggingUtils.getLogListAppender(DmaapMessageHandler.class, WARN);
index be2fabd..72b2060 100644 (file)
@@ -49,6 +49,7 @@ import java.io.InputStreamReader;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -100,8 +101,8 @@ class RefreshConfigTaskTest {
     CbsClient cbsClient;
 
     private static final String RIC_1_NAME = "ric1";
-    private static final ImmutableRicConfig CORRECT_RIC_CONIFG = ImmutableRicConfig.builder() //
-        .name(RIC_1_NAME) //
+    private static final RicConfig CORRECT_RIC_CONIFG = ImmutableRicConfig.builder() //
+        .ricId(RIC_1_NAME) //
         .baseUrl("http://localhost:8080/") //
         .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
         .controllerName("") //
@@ -327,7 +328,7 @@ class RefreshConfigTaskTest {
 
     private RicConfig getRicConfig(String name) {
         RicConfig ricConfig = ImmutableRicConfig.builder() //
-            .name(name) //
+            .ricId(name) //
             .baseUrl("url") //
             .managedElementIds(Collections.emptyList()) //
             .controllerName("controllerName") //
@@ -337,16 +338,16 @@ class RefreshConfigTaskTest {
 
     private Policy getPolicy(Ric ric) {
         ImmutablePolicyType type = ImmutablePolicyType.builder() //
-            .name("type") //
+            .id("type") //
             .schema("{}") //
             .build();
         Policy policy = ImmutablePolicy.builder() //
             .id("id") //
             .type(type) //
-            .lastModified("lastModified") //
+            .lastModified(Instant.now()) //
             .ric(ric) //
             .json("{}") //
-            .ownerServiceName("ownerServiceName") //
+            .ownerServiceId("ownerServiceId") //
             .isTransient(false) //
             .build();
         return policy;
index 6df6e6d..bb3b346 100644 (file)
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -59,12 +60,12 @@ import reactor.core.publisher.Mono;
 class RicSupervisionTest {
     private static final String POLICY_TYPE_1_NAME = "type1";
     private static final PolicyType POLICY_TYPE_1 = ImmutablePolicyType.builder() //
-        .name(POLICY_TYPE_1_NAME) //
+        .id(POLICY_TYPE_1_NAME) //
         .schema("") //
         .build();
 
     private static final Ric RIC_1 = new Ric(ImmutableRicConfig.builder() //
-        .name("RIC_1") //
+        .ricId("ric_1") //
         .baseUrl("baseUrl1") //
         .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
         .controllerName("controllerName") //
@@ -74,20 +75,20 @@ class RicSupervisionTest {
     private static final Policy POLICY_1 = ImmutablePolicy.builder() //
         .id(POLICY_1_ID) //
         .json("") //
-        .ownerServiceName("service") //
+        .ownerServiceId("service") //
         .ric(RIC_1) //
         .type(POLICY_TYPE_1) //
-        .lastModified("now") //
+        .lastModified(Instant.now()) //
         .isTransient(false) //
         .build();
 
     private static final Policy POLICY_2 = ImmutablePolicy.builder() //
         .id("policyId2") //
         .json("") //
-        .ownerServiceName("service") //
+        .ownerServiceId("service") //
         .ric(RIC_1) //
         .type(POLICY_TYPE_1) //
-        .lastModified("now") //
+        .lastModified(Instant.now()) //
         .isTransient(false) //
         .build();
 
@@ -284,7 +285,7 @@ class RicSupervisionTest {
     void whenRicIdleAndSameAmountOfPolicyTypesButNotSameTypes_thenSynchronization() {
         doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
         PolicyType policyType2 = ImmutablePolicyType.builder() //
-            .name("policyType2") //
+            .id("policyType2") //
             .schema("") //
             .build();
 
index 0a84995..93d252f 100644 (file)
@@ -37,6 +37,7 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.read.ListAppender;
 
 import java.time.Duration;
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Collections;
 
@@ -68,13 +69,13 @@ import reactor.core.publisher.Mono;
 class RicSynchronizationTaskTest {
     private static final String POLICY_TYPE_1_NAME = "type1";
     private static final PolicyType POLICY_TYPE_1 = ImmutablePolicyType.builder() //
-        .name(POLICY_TYPE_1_NAME) //
+        .id(POLICY_TYPE_1_NAME) //
         .schema("") //
         .build();
 
     private static final String RIC_1_NAME = "ric1";
     private static final Ric RIC_1 = new Ric(ImmutableRicConfig.builder() //
-        .name(RIC_1_NAME) //
+        .ricId(RIC_1_NAME) //
         .baseUrl("baseUrl1") //
         .managedElementIds(Collections.emptyList()) //
         .controllerName("controllerName") //
@@ -84,10 +85,10 @@ class RicSynchronizationTaskTest {
         return ImmutablePolicy.builder() //
             .id(policyId) //
             .json("") //
-            .ownerServiceName("service") //
+            .ownerServiceId("service") //
             .ric(RIC_1) //
             .type(POLICY_TYPE_1) //
-            .lastModified("now") //
+            .lastModified(Instant.now()) //
             .isTransient(isTransient) //
             .build();
     }
index 5fb2697..3e7bea6 100644 (file)
@@ -33,6 +33,7 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.read.ListAppender;
 
 import java.time.Duration;
+import java.time.Instant;
 import java.util.Collections;
 
 import org.awaitility.Durations;
@@ -71,23 +72,23 @@ class ServiceSupervisionTest {
     private Service service;
     private Policies policies;
     private RicConfig ricConfig = ImmutableRicConfig.builder() //
-        .name(RIC_NAME) //
+        .ricId(RIC_NAME) //
         .baseUrl("baseUrl") //
         .managedElementIds(Collections.emptyList()) //
         .controllerName("") //
         .build();
     private Ric ric = new Ric(ricConfig);
     private PolicyType policyType = ImmutablePolicyType.builder() //
-        .name("plicyTypeName") //
+        .id("policyTypeName") //
         .schema("schema") //
         .build();
     private Policy policy = ImmutablePolicy.builder() //
         .id(POLICY_ID) //
         .json("json") //
-        .ownerServiceName(SERVICE_NAME) //
+        .ownerServiceId(SERVICE_NAME) //
         .ric(ric) //
         .type(policyType) //
-        .lastModified("lastModified") //
+        .lastModified(Instant.now()) //
         .isTransient(false) //
         .build();
 
index 4a781be..14de691 100644 (file)
@@ -51,7 +51,7 @@ public class MockA1Client implements A1Client {
     public Mono<List<String>> getPolicyTypeIdentities() {
         List<String> result = new Vector<>();
         for (PolicyType p : this.policyTypes.getAll()) {
-            result.add(p.name());
+            result.add(p.id());
         }
         return mono(result);
     }
index 61407a4..d474daa 100644 (file)
@@ -50,16 +50,16 @@ public class MockA1ClientFactory extends A1ClientFactory {
 
     @Override
     public Mono<A1Client> createA1Client(Ric ric) {
-        return Mono.just(getOrCreateA1Client(ric.name()));
+        return Mono.just(getOrCreateA1Client(ric.id()));
     }
 
-    public MockA1Client getOrCreateA1Client(String ricName) {
-        if (!clients.containsKey(ricName)) {
-            logger.debug("Creating client for RIC: {}", ricName);
+    public MockA1Client getOrCreateA1Client(String ricId) {
+        if (!clients.containsKey(ricId)) {
+            logger.debug("Creating client for RIC: {}", ricId);
             MockA1Client client = spy(new MockA1Client(policyTypes, asynchDelay));
-            clients.put(ricName, client);
+            clients.put(ricId, client);
         }
-        return clients.get(ricName);
+        return clients.get(ricId);
     }
 
     public void setPolicyTypes(PolicyTypes policyTypes) {