Introduce rAPP Catalogue API

Change-Id: I0128c5b6405d2efd4de49d4ced200cd9fed6cf96
Issue-ID: NONRTRIC-287
Signed-off-by: elinuxhenrik <henrik.b.andersson@est.tech>
diff --git a/.gitignore b/.gitignore
index e5a2f72..26c6731 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,10 +6,12 @@
 
 # Eclipse
 .checkstyle
+.classpath
+target/
 .sts4-cache
 .project
 .settings
 .pydevproject
 infer-out/
 
-.vscode
\ No newline at end of file
+.vscode
diff --git a/docs/.project b/docs/.project
deleted file mode 100644
index e248a4f..0000000
--- a/docs/.project
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>docs</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-	</buildSpec>
-	<natures>
-	</natures>
-</projectDescription>
diff --git a/docs/api-docs.rst b/docs/api-docs.rst
index 12ff516..9b0608a 100644
--- a/docs/api-docs.rst
+++ b/docs/api-docs.rst
@@ -15,9 +15,10 @@
    :depth: 3
    :local:
 
-The Non-RT RIC consists of two parts, described in the sections below:
+The Non-RT RIC consists of three parts, described in the sections below:
  * The Policy Agent
  * The SDNC A1 Controller
+ * The rAPP Catalogue
 
 
 Policy Agent
@@ -44,6 +45,26 @@
 
 See the README.md file in the nonrtric/sdnc-a1-controller repo for info about how to use it.
 
+rAPP Catalogue
+==============
+
+The Non RT-RIC Service Catalogue provides a way for services to register themselves for other services to discover.
+
+See `RAC API <./rac-api.html>`_ for how to use the API.
+
+.. |swagger-icon| image:: ./images/swagger.png
+                  :width: 40px
+
+.. |yaml-icon| image:: ./images/yaml_logo.png
+                  :width: 40px
+
+
+.. csv-table::
+   :header: "API name", "|swagger-icon|", "|yaml-icon|"
+   :widths: 10,5, 5
+
+   "RAC API", ":download:`link <../r-app-catalogue/api/rac-api.json>`", ":download:`link <../r-app-catalogue/api/rac-api.yaml>`"
+
 Complementary tools
 ===================
 
diff --git a/docs/conf.py b/docs/conf.py
index d620289..a6ae7f9 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -7,9 +7,23 @@
 linkcheck_ignore = [
     'http://localhost.*',
     'http://127.0.0.1.*',
-    'https://gerrit.o-ran-sc.org.*'
+    'https://gerrit.o-ran-sc.org.*',
+    './rac-api.html' #Generated file that doesn't exist at link check.
 ]
 
+extensions = ['sphinxcontrib.redoc', 'sphinx.ext.intersphinx',]
+
+redoc = [
+            {
+                'name': 'RAC API',
+                'page': 'rac-api',
+                'spec': '../r-app-catalogue/api/rac-api.json',
+                'embed': True,
+            }
+        ]
+
+redoc_uri = 'https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js'
+
 #intershpinx mapping with other projects
 intersphinx_mapping = {}
 
diff --git a/docs/images/swagger.png b/docs/images/swagger.png
new file mode 100644
index 0000000..f5a9e0c
--- /dev/null
+++ b/docs/images/swagger.png
Binary files differ
diff --git a/docs/images/yaml_logo.png b/docs/images/yaml_logo.png
new file mode 100644
index 0000000..0492eb4
--- /dev/null
+++ b/docs/images/yaml_logo.png
Binary files differ
diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt
index 09a0c1c..78db685 100644
--- a/docs/requirements-docs.txt
+++ b/docs/requirements-docs.txt
@@ -1,5 +1,12 @@
-sphinx
-sphinx-rtd-theme
-sphinxcontrib-httpdomain
-recommonmark
-lfdocs-conf
+tox
+Sphinx>=2,<4
+doc8
+docutils
+setuptools
+six
+sphinx_rtd_theme>=0.4.3
+sphinxcontrib-needs>=0.2.3
+sphinxcontrib-swaggerdoc
+sphinx_bootstrap_theme
+sphinxcontrib-redoc
+lfdocs-conf
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index cb8302e..f21502f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,6 +36,7 @@
         <module>policy-agent</module>
         <module>sdnc-a1-controller</module>
         <module>enrichment-coordinator-service</module>
+        <module>r-app-catalogue</module>
     </modules>
     <build>
         <plugins>
diff --git a/r-app-catalogue/.gitignore b/r-app-catalogue/.gitignore
new file mode 100644
index 0000000..ad56f2d
--- /dev/null
+++ b/r-app-catalogue/.gitignore
@@ -0,0 +1,3 @@
+.swagger-codegen-ignore
+.swagger-codegen/
+api/README.md
diff --git a/r-app-catalogue/Dockerfile b/r-app-catalogue/Dockerfile
new file mode 100644
index 0000000..a85f57d
--- /dev/null
+++ b/r-app-catalogue/Dockerfile
@@ -0,0 +1,39 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2020 Nordix Foundation.
+# ================================================================================
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+FROM openjdk:11-jre-slim
+
+ARG JAR
+
+WORKDIR /opt/app/r-app-catalogue
+RUN mkdir -p /var/log/r-app-catalogue
+
+EXPOSE 8081 8433
+
+ADD /config/application.yaml /opt/app/r-app-catalogue/config/application.yaml
+ADD target/${JAR} /opt/app/r-app-catalogue/r-app-catalogue.jar
+
+
+RUN chmod -R 777 /opt/app/r-app-catalogue/config/
+
+CMD ["java", "-jar", "/opt/app/r-app-catalogue/r-app-catalogue.jar"]
+
+
+
+
diff --git a/r-app-catalogue/README.md b/r-app-catalogue/README.md
new file mode 100644
index 0000000..863713d
--- /dev/null
+++ b/r-app-catalogue/README.md
@@ -0,0 +1,27 @@
+# O-RAN-SC Non-RT RIC rAPP Catalogue
+
+The O-RAN Non-RT RIC rApp Catalogue provides an OpenApi 3.0 REST API for services to register themselves and discover
+other services.
+
+**NOTE!** The definition of the REST API is done in the `api/rac-api.json` file. The yaml version of the file is
+generated during compilation.
+
+The application is a SpringBoot application generated using the openapitools openapi-generator-maven-plugin.
+
+To start the application run:
+`mvn spring-boot:run`
+
+## License
+
+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.
diff --git a/r-app-catalogue/api/rac-api.json b/r-app-catalogue/api/rac-api.json
new file mode 100644
index 0000000..3741bdd
--- /dev/null
+++ b/r-app-catalogue/api/rac-api.json
@@ -0,0 +1,246 @@
+{
+  "openapi": "3.0.0",
+  "info": {
+    "title": "rAPP Catalogue API",
+    "description": "The Non RT-RIC Service Catalogue provides a way for services to register themselves for other services to discover.",
+    "version": "1.0.0"
+  },
+  "paths": {
+    "/services": {
+      "get": {
+        "summary": "Service names",
+        "deprecated": false,
+        "operationId": "getServiceNamesUsingGET",
+        "responses": {
+          "200": {
+            "description": "Service names",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "type": "string"
+                  }
+                },
+                "example": [
+                  "DroneIdentifier",
+                  "Collector"
+                ]
+              }
+            }
+          },
+          "401": {
+            "description": "Unauthorized"
+          },
+          "403": {
+            "description": "Forbidden"
+          },
+          "404": {
+            "description": "Not used"
+          }
+        },
+        "tags": [
+          "rAPP Catalogue API"
+        ]
+      }
+    },
+    "/services/{serviceName}": {
+      "get": {
+        "summary": "Individual Service",
+        "deprecated": false,
+        "operationId": "getIndividualServiceUsingGET",
+        "responses": {
+          "200": {
+            "description": "EI Job",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/service"
+                }
+              }
+            }
+          },
+          "401": {
+            "description": "Unauthorized"
+          },
+          "403": {
+            "description": "Forbidden"
+          },
+          "404": {
+            "description": "Service is not found",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/error_information"
+                }
+              }
+            }
+          }
+        },
+        "parameters": [
+          {
+            "in": "path",
+            "name": "serviceName",
+            "description": "serviceName",
+            "schema": {
+              "type": "string"
+            },
+            "required": true,
+            "example": "DroneIdentifier"
+          }
+        ],
+        "tags": [
+          "rAPP Catalogue API"
+        ]
+      },
+      "put": {
+        "summary": "Create or update a Service",
+        "deprecated": false,
+        "operationId": "putIndividualServiceUsingPUT",
+        "responses": {
+          "200": {
+            "description": "Service updated"
+          },
+          "201": {
+            "description": "Service created"
+          },
+          "401": {
+            "description": "Unauthorized"
+          },
+          "403": {
+            "description": "Forbidden"
+          },
+          "404": {
+            "description": "Provided service is not correct",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/error_information"
+                },
+                "example": {
+                  "detail": "Service is missing required property version",
+                  "status": 404
+                }
+              }
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "serviceName",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            },
+            "example": "DroneIdentifier"
+          }
+        ],
+        "requestBody": {
+          "description": "Service to create/update",
+          "required": true,
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/service"
+              }
+            }
+          }
+        },
+        "tags": [
+          "rAPP Catalogue API"
+        ]
+      },
+      "delete": {
+        "summary": "Remove a Service from the catalogue",
+        "deprecated": false,
+        "operationId": "deleteIndividualServiceUsingDELETE",
+        "responses": {
+          "200": {
+            "description": "Not used"
+          },
+          "204": {
+            "description": "Job deleted"
+          },
+          "401": {
+            "description": "Unauthorized"
+          },
+          "403": {
+            "description": "Forbidden"
+          },
+          "404": {
+            "description": "Service is not found",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/error_information"
+                }
+              }
+            }
+          }
+        },
+        "parameters": [
+          {
+            "name": "serviceName",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            },
+            "example": "DroneIdentifier"
+          }
+        ],
+        "tags": [
+          "rAPP Catalogue API"
+        ]
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "service": {
+        "description": "A Service",
+        "type": "object",
+        "title": "service",
+        "required": [
+          "version"
+        ],
+        "properties": {
+          "version": {
+            "description": "Version of the Service",
+            "type": "string",
+            "example": "1.0.0"
+          },
+          "display_name": {
+            "description": "Display name for the Service",
+            "type": "string",
+            "example": "Drone Identifier"
+          },
+          "description": {
+            "description": "Description of the Service",
+            "type": "string",
+            "example": "Detects if a UE is a drone"
+          }
+        }
+      },
+      "error_information": {
+        "description": "Problem as defined in https://tools.ietf.org/html/rfc7807",
+        "type": "object",
+        "title": "error_information",
+        "properties": {
+          "detail": {
+            "description": "A human-readable explanation specific to this occurrence of the problem.",
+            "type": "string",
+            "example": "Service not found"
+          },
+          "status": {
+            "format": "int32",
+            "description": "The HTTP status code generated by the origin server for this occurrence of the problem.",
+            "type": "integer",
+            "example": 404
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/r-app-catalogue/api/rac-api.yaml b/r-app-catalogue/api/rac-api.yaml
new file mode 100644
index 0000000..87e2eb9
--- /dev/null
+++ b/r-app-catalogue/api/rac-api.yaml
@@ -0,0 +1,175 @@
+openapi: 3.0.0
+info:
+  title: rAPP Catalogue API
+  description: The Non RT-RIC Service Catalogue provides a way for services to register
+    themselves for other services to discover.
+  version: 1.0.0
+servers:
+- url: /
+paths:
+  /services:
+    get:
+      tags:
+      - rAPP Catalogue API
+      summary: Service names
+      operationId: getServiceNamesUsingGET
+      responses:
+        200:
+          description: Service names
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  type: string
+              example:
+              - DroneIdentifier
+              - Collector
+        401:
+          description: Unauthorized
+        403:
+          description: Forbidden
+        404:
+          description: Not used
+      deprecated: false
+  /services/{serviceName}:
+    get:
+      tags:
+      - rAPP Catalogue API
+      summary: Individual Service
+      operationId: getIndividualServiceUsingGET
+      parameters:
+      - name: serviceName
+        in: path
+        description: serviceName
+        required: true
+        style: simple
+        explode: false
+        schema:
+          type: string
+        example: DroneIdentifier
+      responses:
+        200:
+          description: EI Job
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/service'
+        401:
+          description: Unauthorized
+        403:
+          description: Forbidden
+        404:
+          description: Service is not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/error_information'
+      deprecated: false
+    put:
+      tags:
+      - rAPP Catalogue API
+      summary: Create or update a Service
+      operationId: putIndividualServiceUsingPUT
+      parameters:
+      - name: serviceName
+        in: path
+        required: true
+        style: simple
+        explode: false
+        schema:
+          type: string
+        example: DroneIdentifier
+      requestBody:
+        description: Service to create/update
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/service'
+        required: true
+      responses:
+        200:
+          description: Service updated
+        201:
+          description: Service created
+        401:
+          description: Unauthorized
+        403:
+          description: Forbidden
+        404:
+          description: Provided service is not correct
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/error_information'
+              example:
+                detail: Service is missing required property version
+                status: 404
+      deprecated: false
+    delete:
+      tags:
+      - rAPP Catalogue API
+      summary: Remove a Service from the catalogue
+      operationId: deleteIndividualServiceUsingDELETE
+      parameters:
+      - name: serviceName
+        in: path
+        required: true
+        style: simple
+        explode: false
+        schema:
+          type: string
+        example: DroneIdentifier
+      responses:
+        200:
+          description: Not used
+        204:
+          description: Job deleted
+        401:
+          description: Unauthorized
+        403:
+          description: Forbidden
+        404:
+          description: Service is not found
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/error_information'
+      deprecated: false
+components:
+  schemas:
+    service:
+      title: service
+      required:
+      - version
+      type: object
+      properties:
+        version:
+          type: string
+          description: Version of the Service
+          example: 1.0.0
+        display_name:
+          type: string
+          description: Display name for the Service
+          example: Drone Identifier
+        description:
+          type: string
+          description: Description of the Service
+          example: Detects if a UE is a drone
+      description: A Service
+    error_information:
+      title: error_information
+      type: object
+      properties:
+        detail:
+          type: string
+          description: A human-readable explanation specific to this occurrence of
+            the problem.
+          example: Service not found
+        status:
+          type: integer
+          description: The HTTP status code generated by the origin server for this
+            occurrence of the problem.
+          format: int32
+          example: 404
+      description: Problem as defined in https://tools.ietf.org/html/rfc7807
diff --git a/r-app-catalogue/config/application.yaml b/r-app-catalogue/config/application.yaml
new file mode 100644
index 0000000..fadf7d2
--- /dev/null
+++ b/r-app-catalogue/config/application.yaml
@@ -0,0 +1,4 @@
+spring:
+  profiles:
+    active: prod
+
diff --git a/r-app-catalogue/pom.xml b/r-app-catalogue/pom.xml
new file mode 100644
index 0000000..3ac8562
--- /dev/null
+++ b/r-app-catalogue/pom.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+* ========================LICENSE_START=================================

+* O-RAN-SC

+* %%

+* Copyright (C) 2020 Nordix Foundation

+* %%

+* 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===================================

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

+    <modelVersion>4.0.0</modelVersion>

+

+    <parent>

+        <groupId>org.springframework.boot</groupId>

+        <artifactId>spring-boot-starter-parent</artifactId>

+        <version>2.3.4.RELEASE</version>

+        <relativePath />

+    </parent>

+    <groupId>org.o-ran-sc.nonrtric</groupId>

+    <artifactId>r-app-catalogue</artifactId>

+    <version>1.0.0-SNAPSHOT</version>

+    <licenses>

+        <license>

+            <name>The Apache Software License, Version 2.0</name>

+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>

+        </license>

+    </licenses>

+    <properties>

+        <java.version>11</java.version>

+        <swagger-annotations.version>1.5.22</swagger-annotations.version>

+        <springfox.version>2.9.2</springfox.version>

+        <jackson-databind-nullable.version>0.2.1</jackson-databind-nullable.version>

+        <openapi-generator-maven-plugin.version>4.3.1</openapi-generator-maven-plugin.version>

+        <swagger-codegen-maven-plugin.version>3.0.11</swagger-codegen-maven-plugin.version>

+        <docker-maven-plugin.version>0.30.0</docker-maven-plugin.version>

+    </properties>

+

+    <dependencies>

+        <dependency>

+            <groupId>io.swagger</groupId>

+            <artifactId>swagger-annotations</artifactId>

+            <version>${swagger-annotations.version}</version>

+        </dependency>

+        <dependency>

+            <groupId>com.fasterxml.jackson.core</groupId>

+            <artifactId>jackson-annotations</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.springframework</groupId>

+            <artifactId>spring-beans</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.springframework.boot</groupId>

+            <artifactId>spring-boot-autoconfigure</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.springframework</groupId>

+            <artifactId>spring-web</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.springframework.boot</groupId>

+            <artifactId>spring-boot</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.springframework</groupId>

+            <artifactId>spring-webmvc</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.springframework</groupId>

+            <artifactId>spring-context</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>io.springfox</groupId>

+            <artifactId>springfox-swagger2</artifactId>

+            <version>${springfox.version}</version>

+        </dependency>

+        <dependency>

+            <groupId>io.springfox</groupId>

+            <artifactId>springfox-core</artifactId>

+            <version>${springfox.version}</version>

+        </dependency>

+        <dependency>

+            <groupId>io.springfox</groupId>

+            <artifactId>springfox-spring-web</artifactId>

+            <version>${springfox.version}</version>

+        </dependency>

+        <dependency>

+            <groupId>io.springfox</groupId>

+            <artifactId>springfox-spi</artifactId>

+            <version>${springfox.version}</version>

+        </dependency>

+        <dependency>

+            <groupId>org.assertj</groupId>

+            <artifactId>assertj-core</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.apache.tomcat.embed</groupId>

+            <artifactId>tomcat-embed-core</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.openapitools</groupId>

+            <artifactId>jackson-databind-nullable</artifactId>

+            <version>${jackson-databind-nullable.version}</version>

+        </dependency>

+        <dependency>

+            <groupId>javax.validation</groupId>

+            <artifactId>validation-api</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>com.fasterxml.jackson.core</groupId>

+            <artifactId>jackson-databind</artifactId>

+        </dependency>

+        <dependency>

+            <groupId>org.yaml</groupId>

+            <artifactId>snakeyaml</artifactId>

+            <scope>runtime</scope>

+        </dependency>

+        <!-- TEST -->

+        <dependency>

+            <groupId>org.springframework</groupId>

+            <artifactId>spring-test</artifactId>

+            <scope>test</scope>

+        </dependency>

+        <dependency>

+            <groupId>org.junit.jupiter</groupId>

+            <artifactId>junit-jupiter-api</artifactId>

+            <scope>test</scope>

+        </dependency>

+    </dependencies>

+

+    <build>

+        <plugins>

+            <plugin>

+                <groupId>org.openapitools</groupId>

+                <artifactId>openapi-generator-maven-plugin</artifactId>

+                <version>${openapi-generator-maven-plugin.version}</version>

+                <executions>

+                    <execution>

+                        <goals>

+                            <goal>generate</goal>

+                        </goals>

+                        <configuration>

+                            <inputSpec>${project.basedir}/api/rac-api.json</inputSpec>

+                            <generatorName>spring</generatorName>

+                            <apiPackage>org.oransc.rappcatalogue.api</apiPackage>

+                            <modelPackage>org.oransc.rappcatalogue.model</modelPackage>

+                            <configOptions>

+                                <delegatePattern>true</delegatePattern>

+                            </configOptions>

+                        </configuration>

+                    </execution>

+                </executions>

+            </plugin>

+            <plugin>

+                <groupId>io.swagger.codegen.v3</groupId>

+                <artifactId>swagger-codegen-maven-plugin</artifactId>

+                <version>${swagger-codegen-maven-plugin.version}</version>

+                <executions>

+                    <execution>

+                        <goals>

+                            <goal>generate</goal>

+                        </goals>

+                        <configuration>

+                            <inputSpec>${project.basedir}/api/rac-api.json</inputSpec>

+                            <language>openapi-yaml</language>

+                            <output>${project.basedir}/api/</output>

+                            <configOptions>

+                                <outputFile>rac-api.yaml</outputFile>

+                            </configOptions>

+                        </configuration>

+                    </execution>

+                </executions>

+            </plugin>

+            <plugin>

+                <groupId>io.fabric8</groupId>

+                <artifactId>docker-maven-plugin</artifactId>

+                <version>${docker-maven-plugin.version}</version>

+                <inherited>false</inherited>

+                <executions>

+                    <execution>

+                        <id>generate-r-app-catalogue-image</id>

+                        <phase>package</phase>

+                        <goals>

+                            <goal>build</goal>

+                        </goals>

+                        <configuration>

+                            <pullRegistry>${env.CONTAINER_PULL_REGISTRY}</pullRegistry>

+                            <images>

+                                <image>

+                                    <name>o-ran-sc/nonrtric-r-app-catalogue:${project.version}</name>

+                                    <build>

+                                        <cleanup>try</cleanup>

+                                        <contextDir>${basedir}</contextDir>

+                                        <dockerFile>Dockerfile</dockerFile>

+                                        <args>

+                                            <JAR>${project.build.finalName}.jar</JAR>

+                                        </args>

+                                        <tags>

+                                            <tag>${project.version}</tag>

+                                        </tags>

+                                    </build>

+                                </image>

+                            </images>

+                        </configuration>

+                    </execution>

+                    <execution>

+                        <id>push-r-app-catalogue-image</id>

+                        <goals>

+                            <goal>build</goal>

+                            <goal>push</goal>

+                        </goals>

+                        <configuration>

+                            <pullRegistry>${env.CONTAINER_PULL_REGISTRY}</pullRegistry>

+                            <pushRegistry>${env.CONTAINER_PUSH_REGISTRY}</pushRegistry>

+                            <images>

+                                <image>

+                                    <name>o-ran-sc/nonrtric-r-app-catalogue:${project.version}</name>

+                                    <build>

+                                        <contextDir>${basedir}</contextDir>

+                                        <dockerFile>Dockerfile</dockerFile>

+                                        <args>

+                                            <JAR>${project.build.finalName}.jar</JAR>

+                                        </args>

+                                        <tags>

+                                            <tag>${project.version}</tag>

+                                            <tag>latest</tag>

+                                        </tags>

+                                    </build>

+                                </image>

+                            </images>

+                        </configuration>

+                    </execution>

+                </executions>

+            </plugin>

+        </plugins>

+    </build>

+</project>
\ No newline at end of file
diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java
new file mode 100644
index 0000000..701f1d8
--- /dev/null
+++ b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java
@@ -0,0 +1,34 @@
+package org.oransc.rappcatalogue.api;

+

+import java.util.Arrays;

+import java.util.List;

+

+import org.springframework.http.HttpStatus;

+import org.springframework.http.ResponseEntity;

+

+@org.springframework.stereotype.Service

+public class ServicesApiDelegateImpl implements ServicesApiDelegate {

+

+    @Override

+    public ResponseEntity<Void> deleteIndividualServiceUsingDELETE(String serviceName) {

+        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

+    }

+

+    // @Override

+    // public ResponseEntity<Service> getIndividualServiceUsingGET(String serviceName) {

+    //     return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

+

+    // }

+

+    @Override

+    public ResponseEntity<List<String>> getServiceNamesUsingGET() {

+        List<String> services = Arrays.asList("a", "b");

+        return ResponseEntity.ok(services);

+    }

+

+    // @Override

+    // public ResponseEntity<Void> putIndividualServiceUsingPUT(String serviceName, Service service) {

+    //     return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

+

+    // }

+}

diff --git a/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java b/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java
new file mode 100644
index 0000000..53dfc1a
--- /dev/null
+++ b/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java
@@ -0,0 +1,33 @@
+package org.oransc.rappcatalogue.api;

+

+import static org.assertj.core.api.Assertions.assertThat;

+

+import java.util.Arrays;

+import java.util.List;

+

+import org.junit.jupiter.api.Test;

+import org.junit.jupiter.api.extension.ExtendWith;

+import org.springframework.http.HttpStatus;

+import org.springframework.http.ResponseEntity;

+import org.springframework.test.context.junit.jupiter.SpringExtension;

+

+@ExtendWith(SpringExtension.class)

+class ServicesApiDelegateImplTest {

+

+    @Test

+    void putValidService_shouldBeOk() {

+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl();

+

+        ResponseEntity<List<String>> response = delegateUnderTest.getServiceNamesUsingGET();

+    }

+

+    @Test

+    void getServices_shouldProvideArrayOfServices() throws Exception {

+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl();

+

+        ResponseEntity<List<String>> response = delegateUnderTest.getServiceNamesUsingGET();

+

+        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

+        assertThat(response.getBody()).isEqualTo(Arrays.asList("a", "b"));

+    }

+}

diff --git a/tox.ini b/tox.ini
index 4491722..2705e16 100644
--- a/tox.ini
+++ b/tox.ini
@@ -24,23 +24,14 @@
 
 [testenv:docs]
 basepython = python3
-deps =
-    sphinx
-    sphinx-rtd-theme
-    sphinxcontrib-httpdomain
-    recommonmark
-    lfdocs-conf
+deps = -r{toxinidir}/docs/requirements-docs.txt
 
 commands =
-    sphinx-build -W -b html -n -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/html
+    sphinx-build -W -b html -n -d {envtmpdir}/docs/doctrees ./docs/ {toxinidir}/docs/_build/html
     echo "Generated docs available in {toxinidir}/docs/_build/html"
 whitelist_externals = echo
 
 [testenv:docs-linkcheck]
 basepython = python3
-deps = sphinx
-       sphinx-rtd-theme
-       sphinxcontrib-httpdomain
-       recommonmark
-       lfdocs-conf
+deps = -r{toxinidir}/docs/requirements-docs.txt
 commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees ./docs/ {toxinidir}/docs/_build/linkcheck