--- /dev/null
+#==================================================================================
+# Copyright (C) 2024: OpenInfra Foundation Europe
+#
+# 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.
+#
+# This source code is part of the near-RT RIC (RAN Intelligent Controller)
+# platform project (RICP).
+#==================================================================================
+
+
+# Use Maven image with OpenJDK 17 for the build stage
+FROM maven:3.8.5-openjdk-17 AS maven_build
+
+# Copy Maven project files
+COPY pom.xml /tmp/
+COPY src /tmp/src/
+
+# Set working directory
+WORKDIR /tmp/
+
+# Build the Maven project
+RUN mvn package
+
+# Use a separate image with OpenJDK 17 for the runtime stage
+FROM openjdk:17-jdk-slim
+
+# Expose port 8080
+EXPOSE 8080
+
+# Set the working directory
+WORKDIR /app
+
+# Copy the JAR file from the maven_build stage to the runtime stage
+COPY --from=maven_build /tmp/target/hello-world-sme-invoker-0.1.0.jar /app/hello-world-sme-invoker-0.1.0.jar
+
+# Command to run the application
+CMD ["java", "-jar", "hello-world-sme-invoker-0.1.0.jar"]
--- /dev/null
+# Hello World Sme Invoker Service\r
+\r
+This repository contains a Spring Boot application serving few Hello World SME endpoints. \r
+The application can be built and run using the provided script - ``hello-world-sme-invoker-build-start.sh``.\r
+\r
+## Prerequisites\r
+\r
+- Docker installed on your machine.\r
+\r
+## Building and Running the Application\r
+Run the script:\r
+\r
+```bash\r
+ ./hello-world-sme-invoker-build-start.sh\r
+```\r
+\r
+The script will build a Docker image and run a container with the Hello World SME service. After the container starts,\r
+wait for a few seconds to ensure the Spring Boot application is fully initialized. Next, it will make an HTTP request to the\r
+Hello World SME endpoint and display the response:\r
+\r
+```bash\r
+ response=$(curl -s http://localhost:8080/helloworld/v1/sme)\r
+ echo "Response from the Hello World SME endpoint:"\r
+ echo "$response"\r
+```\r
+\r
+To stop and remove the Docker container:\r
+\r
+```bash\r
+ docker stop hello-world-sme-invoker\r
+ docker rm hello-world-sme-invoker\r
+```\r
+\r
+## Additional Information\r
+\r
+- The Hello World SME endpoint is available at http://localhost:8080/helloworld/v1/sme.\r
+\r
--- /dev/null
+#!/bin/bash
+
+# ============LICENSE_START===============================================
+# Copyright (C) 2024: OpenInfra Foundation Europe.
+# ========================================================================
+# 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=================================================
+#
+
+# Build image from Dockerfile with/without custom image tag
+# Optionally push to external image repo
+
+print_usage() {
+ echo "Usage: build.sh no-push|<docker-hub-repo-name> [<image-tag>]"
+ exit 1
+}
+
+if [ $# -ne 1 ] && [ $# -ne 2 ]; then
+ print_usage
+fi
+
+IMAGE_NAME="nonrtric-sample-helloworld-sme-invoker"
+IMAGE_TAG="latest"
+REPO=""
+if [ $1 == "no-push" ]; then
+ echo "Only local image build"
+else
+ REPO=$1
+ echo "Attempt to push built image to: "$REPO
+fi
+
+shift
+while [ $# -ne 0 ]; do
+ if [ $1 == "--tag" ]; then
+ shift
+ if [ -z "$1" ]; then
+ print_usage
+ fi
+ IMAGE_TAG=$1
+ echo "Setting image tag to: "$IMAGE_TAG
+ shift
+ else
+ echo "Unknown parameter: $1"
+ print_usage
+ fi
+done
+
+IMAGE=$IMAGE_NAME:$IMAGE_TAG
+
+export DOCKER_DEFAULT_PLATFORM=linux/amd64
+CURRENT_PLATFORM=$(docker system info --format '{{.OSType}}/{{.Architecture}}')
+if [ $CURRENT_PLATFORM != $DOCKER_DEFAULT_PLATFORM ]; then
+ echo "Image may not work on the current platform: $CURRENT_PLATFORM, only platform $DOCKER_DEFAULT_PLATFORM supported"
+fi
+
+echo "Building image $IMAGE"
+docker build -t $IMAGE_NAME:$IMAGE_TAG .
+if [ $? -ne 0 ]; then
+ echo "BUILD FAILED"
+ exit 1
+fi
+echo "BUILD OK"
+
+if [ "$REPO" != "" ]; then
+ echo "Tagging image"
+ NEW_IMAGE=$REPO/$IMAGE_NAME:$IMAGE_TAG
+ docker tag $IMAGE $NEW_IMAGE
+ if [ $? -ne 0 ]; then
+ echo "RE-TAGGING FAILED"
+ exit 1
+ fi
+ echo "RE-TAG OK"
+
+ echo "Pushing image $NEW_IMAGE"
+ docker push $NEW_IMAGE
+ if [ $? -ne 0 ]; then
+ echo "PUSHED FAILED"
+ echo " Perhaps not logged into docker-hub repo $REPO?"
+ exit 1
+ fi
+ IMAGE=$NEW_IMAGE
+ echo "PUSH OK"
+fi
+
+echo "IMAGE OK: $IMAGE"
+echo "DONE"
--- /dev/null
+# -
+# ========================LICENSE_START=================================
+# O-RAN-SC
+# %%
+# Copyright (C) 2024: OpenInfra Foundation Europe.
+# %%
+# 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===================================
+#
+
+# The Jenkins job requires a tag to build the Docker image.
+# By default this file is in the docker build directory,
+# but the location can configured in the JJB template.
+---
+tag: 0.1.0
--- /dev/null
+# -
+# ========================LICENSE_START=================================
+# O-RAN-SC
+# %%
+# Copyright (C) 2024: OpenInfra Foundation Europe
+# %%
+# 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===================================
+#
+
+version: "3.0"
+
+services:
+ hello-world-sme-invoker:
+ build:
+ context: ../../sample-services/hello-world-sme-invoker
+ dockerfile: Dockerfile
+ ports:
+ - 8080:8080
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+
+# -
+# ========================LICENSE_START=================================
+# O-RAN-SC
+# %%
+# Copyright (C) 2024: OpenInfra Foundation Europe.
+# %%
+# 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===================================
+#
+
+NAME="hello-world-sme-invoker"
+IMAGE_NAME="nonrtric-sample-helloworld-sme-invoker"
+
+docker build -t $IMAGE_NAME:latest .
+
+docker run --rm -d -p 8080:8080 --name $NAME $IMAGE_NAME
+
+sleep 10
+
+echo "Make an HTTP request to the Hello World Sme Invoker endpoint and display the response"
+response=$(curl -s http://localhost:8080/helloworld/v1/sme)
+echo "Response from the /helloworld/v1/sme endpoint: "
+echo "$response"
--- /dev/null
+# -\r
+# ========================LICENSE_START=================================\r
+# O-RAN-SC\r
+# %%\r
+# Copyright (C) 2024: OpenInfra Foundation Europe\r
+# %%\r
+# Licensed under the Apache License, Version 2.0 (the "License");\r
+# you may not use this file except in compliance with the License.\r
+# You may obtain a copy of the License at\r
+#\r
+# http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+# Unless required by applicable law or agreed to in writing, software\r
+# distributed under the License is distributed on an "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+# See the License for the specific language governing permissions and\r
+# limitations under the License.\r
+# ========================LICENSE_END===================================\r
+#\r
+\r
+apiVersion: v2\r
+name: hello-world-sme-invoker\r
+description: A Helm chart for NONRTRIC Hello World SME Invoker\r
+\r
+# A chart can be either an 'application' or a 'library' chart.\r
+#\r
+# Application charts are a collection of templates that can be packaged into versioned archives\r
+# to be deployed.\r
+#\r
+# Library charts provide useful utilities or functions for the chart developer. They're included as\r
+# a dependency of application charts to inject those utilities and functions into the rendering\r
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.\r
+type: application\r
+\r
+# This is the chart version. This version number should be incremented each time you make changes\r
+# to the chart and its templates, including the app version.\r
+# Versions are expected to follow Semantic Versioning (https://semver.org/)\r
+version: 0.1.0\r
+\r
+# This is the version number of the application being deployed. This version number should be\r
+# incremented each time you make changes to the application. Versions are not expected to\r
+# follow Semantic Versioning. They should reflect the version the application is using.\r
+# It is recommended to use it with quotes.\r
+appVersion: "0.1.0"\r
--- /dev/null
+# -
+# ========================LICENSE_START=================================
+# O-RAN-SC
+# %%
+# Copyright (C) 2024: OpenInfra Foundation Europe
+# %%
+# 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===================================
+#
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ include "hello-world-sme-invoker.fullname" . }}
+ labels:
+ {{- include "hello-world-sme-invoker.labels" . | nindent 4 }}
+spec:
+ replicas: {{ .Values.replicaCount }}
+ selector:
+ matchLabels:
+ {{- include "hello-world-sme-invoker.selectorLabels" . | nindent 8 }}
+ template:
+ metadata:
+ labels:
+ {{- include "hello-world-sme-invoker.selectorLabels" . | nindent 12 }}
+ spec:
+ containers:
+ - name: {{ .Chart.Name }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+ env:
+ - name: RAPP_INSTANCE_ID
+ value: "{{ .Values.environment.RAPP_INSTANCE_ID }}"
+ - name: SME_DISCOVERY_ENDPOINT
+ value: "{{ .Values.environment.SME_DISCOVERY_ENDPOINT }}"
+ ports:
+ - name: http
+ containerPort: {{ .Values.service.port }}
+
# ========================LICENSE_START=================================
# O-RAN-SC
# %%
-# Copyright (C) 2023: OpenInfra Foundation Europe
+# Copyright (C) 2024: OpenInfra Foundation Europe
# %%
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
apiVersion: v1
-kind: Pod
+kind: Service
metadata:
- name: "{{ include "hello-world-chart.fullname" . }}-test-connection"
+ name: {{ include "hello-world-sme-invoker.fullname" . }}
labels:
- {{- include "hello-world-chart.labels" . | nindent 4 }}
- annotations:
- "helm.sh/hook": test
+ {{- include "hello-world-sme-invoker.labels" . | nindent 4 }}
spec:
- containers:
- - name: wget
- image: busybox
- command: ['wget']
- args: ['{{ include "hello-world-chart.fullname" . }}:{{ .Values.service.port }}']
- restartPolicy: Never
+ type: {{ .Values.service.type }}
+ ports:
+ - port: {{ .Values.service.port }}
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ {{- include "hello-world-sme-invoker.selectorLabels" . | nindent 4 }}
+
--- /dev/null
+# -
+# ========================LICENSE_START=================================
+# O-RAN-SC
+# %%
+# Copyright (C) 2024: OpenInfra Foundation Europe
+# %%
+# 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===================================
+#
+
+image:
+ repository: nexus3.o-ran-sc.org:10003/nonrtric-sample-helloworld-sme-invoker
+ tag: latest
+
+service:
+ name: hello-world-sme-invoker
+ type: ClusterIP
+ port: 8080
+
+environment:
+ APP_ID: Invoker_Rapp_Id
+ SME_DISCOVERY_ENDPOINT: capifcore.nonrtric.svc.cluster.local:8090/service-apis/v1/allServiceAPIs
+
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+\r
+<!--\r
+* ========================LICENSE_START=================================\r
+* O-RAN-SC\r
+* %%\r
+* Copyright (C) 2024 OpenInfra Foundation Europe.\r
+* %%\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ========================LICENSE_END===================================\r
+-->\r
+\r
+<project xmlns="http://maven.apache.org/POM/4.0.0"\r
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+ <modelVersion>4.0.0</modelVersion>\r
+\r
+ <parent>\r
+ <groupId>org.springframework.boot</groupId>\r
+ <artifactId>spring-boot-starter-parent</artifactId>\r
+ <version>3.2.3</version>\r
+ </parent>\r
+\r
+ <groupId>org.o-ran-sc.nonrtric.plt</groupId>\r
+ <artifactId>hello-world-sme-invoker</artifactId>\r
+ <version>0.1.0</version>\r
+\r
+ <properties>\r
+ <maven.compiler.source>17</maven.compiler.source>\r
+ <maven.compiler.target>17</maven.compiler.target>\r
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\r
+ </properties>\r
+\r
+ <dependencies>\r
+ <dependency>\r
+ <groupId>org.springframework.boot</groupId>\r
+ <artifactId>spring-boot-starter-web</artifactId>\r
+ </dependency>\r
+\r
+ <dependency>\r
+ <groupId>org.springframework.boot</groupId>\r
+ <artifactId>spring-boot-starter-test</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+\r
+ <dependency>\r
+ <groupId>org.mockito</groupId>\r
+ <artifactId>mockito-core</artifactId>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ </dependencies>\r
+\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.springframework.boot</groupId>\r
+ <artifactId>spring-boot-maven-plugin</artifactId>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+\r
+</project>
\ No newline at end of file
--- /dev/null
+/*-\r
+ * ========================LICENSE_START=================================\r
+ * O-RAN-SC\r
+ * %%\r
+ * Copyright (C) 2024 OpenInfra Foundation Europe.\r
+ * %%\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ========================LICENSE_END===================================\r
+ */\r
+\r
+package org.oransc.nonrtric.sample;\r
+\r
+import org.springframework.boot.SpringApplication;\r
+import org.springframework.boot.autoconfigure.SpringBootApplication;\r
+import org.springframework.boot.web.client.RestTemplateBuilder;\r
+import org.springframework.context.annotation.Bean;\r
+import org.springframework.web.client.RestTemplate;\r
+\r
+@SpringBootApplication(scanBasePackages = "org.oransc.nonrtric.sample")\r
+public class HelloWorldSmeInvokerApplication {\r
+ public static void main(String[] args) {\r
+ SpringApplication.run(HelloWorldSmeInvokerApplication.class, args);\r
+ }\r
+\r
+ @Bean\r
+ public RestTemplate restTemplate(RestTemplateBuilder builder) {\r
+ return builder.build();\r
+ }\r
+}\r
--- /dev/null
+/*-\r
+ * ========================LICENSE_START=================================\r
+ * O-RAN-SC\r
+ * %%\r
+ * Copyright (C) 2024 OpenInfra Foundation Europe.\r
+ * %%\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ========================LICENSE_END===================================\r
+ */\r
+\r
+package org.oransc.nonrtric.sample.exception;\r
+\r
+public class CapifAccessException extends RuntimeException {\r
+ public CapifAccessException(String message) {\r
+ super(message);\r
+ }\r
+}\r
+\r
--- /dev/null
+/*-\r
+ * ========================LICENSE_START=================================\r
+ * O-RAN-SC\r
+ * %%\r
+ * Copyright (C) 2024 OpenInfra Foundation Europe.\r
+ * %%\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ========================LICENSE_END===================================\r
+ */\r
+\r
+package org.oransc.nonrtric.sample.exception;\r
+\r
+import org.springframework.http.HttpStatus;\r
+import org.springframework.http.MediaType;\r
+import org.springframework.http.ResponseEntity;\r
+import org.springframework.web.bind.annotation.ControllerAdvice;\r
+import org.springframework.web.bind.annotation.ExceptionHandler;\r
+\r
+@ControllerAdvice\r
+public class GlobalExceptionHandler {\r
+\r
+ @ExceptionHandler(CapifAccessException.class)\r
+ public ResponseEntity<String> handleCapifAccessException(CapifAccessException ex) {\r
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)\r
+ .contentType(MediaType.TEXT_PLAIN)\r
+ .body(ex.getMessage());\r
+ }\r
+}\r
+\r
--- /dev/null
+/*-\r
+ * ========================LICENSE_START=================================\r
+ * O-RAN-SC\r
+ * %%\r
+ * Copyright (C) 2024 OpenInfra Foundation Europe.\r
+ * %%\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ========================LICENSE_END===================================\r
+ */\r
+\r
+package org.oransc.nonrtric.sample.rest;\r
+\r
+import jakarta.servlet.http.HttpServletRequest;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import org.oransc.nonrtric.sample.exception.CapifAccessException;\r
+import org.oransc.nonrtric.sample.rest.response.ApiResponse;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+import org.springframework.http.ResponseEntity;\r
+import org.springframework.web.bind.annotation.RequestMapping;\r
+import org.springframework.web.bind.annotation.RestController;\r
+import org.springframework.web.client.RestTemplate;\r
+\r
+@RestController\r
+public class HelloWorldSmeInvokerController {\r
+\r
+ private final RestTemplate restTemplate;\r
+ private static final Logger logger = LoggerFactory.getLogger(HelloWorldSmeInvokerController.class);\r
+\r
+ public HelloWorldSmeInvokerController(RestTemplate restTemplate) {\r
+ this.restTemplate = restTemplate;\r
+ }\r
+\r
+ @RequestMapping("/helloworld/v1/sme")\r
+ public String helloWorld(HttpServletRequest request) {\r
+ String path = logRequestPath(request);\r
+ return "Hello from " + path;\r
+ }\r
+\r
+ @RequestMapping("/helloworld/sme/invoker/v1/apiset")\r
+ public ResponseEntity<ApiResponse> helloWorldSmeInvoker(HttpServletRequest request) {\r
+ String path = logRequestPath(request);\r
+ String capifUrl = createCapifUrl();\r
+ try {\r
+ ApiResponse apiResponse = restTemplate.getForObject(capifUrl, ApiResponse.class);\r
+ return ResponseEntity.ok(apiResponse);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new CapifAccessException("Error accessing the URL :- "+capifUrl);\r
+ } catch (Exception e) {\r
+ throw new CapifAccessException("Unexpected error");\r
+ }\r
+ }\r
+\r
+ @RequestMapping("/helloworld/sme/invoker/v1")\r
+ public ResponseEntity<String> accessHelloWorldByInvoker(HttpServletRequest request) {\r
+ String path = logRequestPath(request);\r
+ String capifUrl = createCapifUrl();\r
+ String baseUrl = "";\r
+ ApiResponse apiResponse = new ApiResponse();\r
+ try {\r
+ apiResponse = restTemplate.getForObject(capifUrl, ApiResponse.class);\r
+ baseUrl = getBaseUrl(apiResponse);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new CapifAccessException("Error accessing the URL :- "+capifUrl);\r
+ } catch (Exception e) {\r
+ throw new CapifAccessException("Unexpected error");\r
+ }\r
+\r
+ String helloWorldEndpoint = "";\r
+ List<String> apiSetEndpoints = getApiSetEndpoints(apiResponse, baseUrl);\r
+ if(apiSetEndpoints != null && !apiSetEndpoints.isEmpty()){\r
+ helloWorldEndpoint = apiSetEndpoints.get(0);\r
+ }\r
+\r
+ try {\r
+ String responseHelloWorld = restTemplate.getForObject(helloWorldEndpoint, String.class);\r
+ logger.info("Response :- ", responseHelloWorld);\r
+ return ResponseEntity.ok(responseHelloWorld);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new CapifAccessException("Error accessing the URL :- "+helloWorldEndpoint);\r
+ } catch (Exception e) {\r
+ throw new CapifAccessException("Unexpected error");\r
+ }\r
+ }\r
+\r
+ private String logRequestPath(HttpServletRequest request) {\r
+ String path = request.getRequestURI();\r
+ logger.info("Received request for path: {}", path);\r
+ return path;\r
+ }\r
+\r
+ private String createCapifUrl() {\r
+ String appId = System.getenv("APP_ID");\r
+ if (appId != null) {\r
+ logger.info("APP_ID: " + appId);\r
+ } else {\r
+ logger.info("APP_ID environment variable is not set. ");\r
+ appId = "Invoker_App_1";\r
+ logger.info("APP_ID default value :- " + appId);\r
+ }\r
+\r
+ String smeDiscoveryEndpoint = System.getenv("SME_DISCOVERY_ENDPOINT");\r
+ if (smeDiscoveryEndpoint != null) {\r
+ logger.info("SME_DISCOVERY_ENDPOINT: " + smeDiscoveryEndpoint);\r
+ } else {\r
+ logger.info("SME_DISCOVERY_ENDPOINT environment variable is not set.");\r
+ smeDiscoveryEndpoint = "capifcore.nonrtric.svc.cluster.local:8090/service-apis/v1/allServiceAPIs";\r
+ logger.info("SME_DISCOVERY_ENDPOINT default value :- " + smeDiscoveryEndpoint);\r
+ }\r
+\r
+ String invokerId = "api_invoker_id_Invoker_App_1";\r
+ if (appId != null) {\r
+ invokerId = "api_invoker_id_" + appId;\r
+ }\r
+ logger.info("invokerId: " + invokerId);\r
+\r
+ String capifUrl =\r
+ "http://capifcore.nonrtric.svc.cluster.local:8090/service-apis/v1/allServiceAPIs" + "?api-invoker-id=" +\r
+ invokerId;\r
+ if (smeDiscoveryEndpoint != null) {\r
+ capifUrl = smeDiscoveryEndpoint + "?api-invoker-id=" + invokerId;\r
+ }\r
+ logger.info("capifUrl: " + capifUrl);\r
+\r
+ return capifUrl;\r
+ }\r
+\r
+ private static String getBaseUrl(ApiResponse apiResponse) {\r
+ if (apiResponse != null &&\r
+ apiResponse.getServiceAPIDescriptions() != null &&\r
+ !apiResponse.getServiceAPIDescriptions().isEmpty()) {\r
+\r
+ ApiResponse.ServiceAPIDescription serviceAPIDescription = apiResponse.getServiceAPIDescriptions().get(0);\r
+\r
+ if (serviceAPIDescription.getAefProfiles() != null &&\r
+ !serviceAPIDescription.getAefProfiles().isEmpty()) {\r
+\r
+ ApiResponse.AefProfile aefProfile = serviceAPIDescription.getAefProfiles().get(0);\r
+\r
+ if (aefProfile.getInterfaceDescriptions() != null &&\r
+ !aefProfile.getInterfaceDescriptions().isEmpty()) {\r
+ ApiResponse.InterfaceDescription interfaceDescription = aefProfile.getInterfaceDescriptions().get(0);\r
+ return "http://" + interfaceDescription.getIpv4Addr() + ":" + interfaceDescription.getPort();\r
+ }\r
+ }\r
+ }\r
+ return "";\r
+ }\r
+\r
+ private static List<String> getApiSetEndpoints(ApiResponse apiResponse, String baseUrl){\r
+\r
+ String helloWorldEndpoint = "";\r
+ List<String> apiSetEndpoints = new ArrayList<>(5);\r
+\r
+ if (apiResponse != null &&\r
+ apiResponse.getServiceAPIDescriptions() != null &&\r
+ !apiResponse.getServiceAPIDescriptions().isEmpty()) {\r
+\r
+ ApiResponse.ServiceAPIDescription serviceAPIDescription = apiResponse.getServiceAPIDescriptions().get(0);\r
+\r
+ if (serviceAPIDescription.getAefProfiles() != null &&\r
+ !serviceAPIDescription.getAefProfiles().isEmpty()) {\r
+\r
+ ApiResponse.AefProfile aefProfile = serviceAPIDescription.getAefProfiles().get(0);\r
+\r
+ if (aefProfile.getInterfaceDescriptions() != null &&\r
+ !aefProfile.getInterfaceDescriptions().isEmpty()) {\r
+\r
+ ApiResponse.InterfaceDescription interfaceDescription = aefProfile.getInterfaceDescriptions().get(0);\r
+\r
+ if (aefProfile.getVersions() != null &&\r
+ !aefProfile.getVersions().isEmpty()) {\r
+\r
+ ApiResponse.ApiVersion apiVersion = aefProfile.getVersions().get(0);\r
+\r
+ if (apiVersion.getResources() != null &&\r
+ !apiVersion.getResources().isEmpty()) {\r
+\r
+ for(ApiResponse.Resource resource : apiVersion.getResources()) {\r
+ helloWorldEndpoint = baseUrl + resource.getUri();\r
+ logger.info("Complete URL for resource " + helloWorldEndpoint);\r
+ apiSetEndpoints.add(helloWorldEndpoint);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return apiSetEndpoints;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*-\r
+ * ========================LICENSE_START=================================\r
+ * O-RAN-SC\r
+ * %%\r
+ * Copyright (C) 2024 OpenInfra Foundation Europe.\r
+ * %%\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ========================LICENSE_END===================================\r
+ */\r
+\r
+package org.oransc.nonrtric.sample.rest.response;\r
+\r
+import com.fasterxml.jackson.annotation.JsonProperty;\r
+import java.util.List;\r
+\r
+public class ApiResponse {\r
+\r
+ @JsonProperty("serviceAPIDescriptions")\r
+ private List<ServiceAPIDescription> serviceAPIDescriptions;\r
+\r
+ public List<ServiceAPIDescription> getServiceAPIDescriptions() {\r
+ return serviceAPIDescriptions;\r
+ }\r
+\r
+ public void setServiceAPIDescriptions(List<ServiceAPIDescription> serviceAPIDescriptions) {\r
+ this.serviceAPIDescriptions = serviceAPIDescriptions;\r
+ }\r
+\r
+ public static class ServiceAPIDescription {\r
+ @JsonProperty("apiName")\r
+ private String apiName;\r
+\r
+ @JsonProperty("apiId")\r
+ private String apiId;\r
+\r
+ @JsonProperty("description")\r
+ private String description;\r
+\r
+ @JsonProperty("aefProfiles")\r
+ private List<AefProfile> aefProfiles;\r
+\r
+ public String getApiName() {\r
+ return apiName;\r
+ }\r
+\r
+ public void setApiName(String apiName) {\r
+ this.apiName = apiName;\r
+ }\r
+\r
+ public String getApiId() {\r
+ return apiId;\r
+ }\r
+\r
+ public void setApiId(String apiId) {\r
+ this.apiId = apiId;\r
+ }\r
+\r
+ public String getDescription() {\r
+ return description;\r
+ }\r
+\r
+ public void setDescription(String description) {\r
+ this.description = description;\r
+ }\r
+\r
+ public List<AefProfile> getAefProfiles() {\r
+ return aefProfiles;\r
+ }\r
+\r
+ public void setAefProfiles(List<AefProfile> aefProfiles) {\r
+ this.aefProfiles = aefProfiles;\r
+ }\r
+ }\r
+\r
+ public static class AefProfile {\r
+ private String aefId;\r
+ private String domainName;\r
+ private List<ApiVersion> versions;\r
+ private String protocol;\r
+ private List<InterfaceDescription> interfaceDescriptions;\r
+\r
+ public String getAefId() {\r
+ return aefId;\r
+ }\r
+\r
+ public String getDomainName() {\r
+ return domainName;\r
+ }\r
+\r
+ public void setDomainName(String domainName) {\r
+ this.domainName = domainName;\r
+ }\r
+\r
+ public void setAefId(String aefId) {\r
+ this.aefId = aefId;\r
+ }\r
+\r
+ public List<ApiVersion> getVersions() {\r
+ return versions;\r
+ }\r
+\r
+ public void setVersions(List<ApiVersion> versions) {\r
+ this.versions = versions;\r
+ }\r
+\r
+ public String getProtocol() {\r
+ return protocol;\r
+ }\r
+\r
+ public void setProtocol(String protocol) {\r
+ this.protocol = protocol;\r
+ }\r
+\r
+ public List<InterfaceDescription> getInterfaceDescriptions() {\r
+ return interfaceDescriptions;\r
+ }\r
+\r
+ public void setInterfaceDescriptions(\r
+ List<InterfaceDescription> interfaceDescriptions) {\r
+ this.interfaceDescriptions = interfaceDescriptions;\r
+ }\r
+ }\r
+\r
+ public static class ApiVersion {\r
+ private String apiVersion;\r
+ private List<Resource> resources;\r
+\r
+ public String getApiVersion() {\r
+ return apiVersion;\r
+ }\r
+\r
+ public void setApiVersion(String apiVersion) {\r
+ this.apiVersion = apiVersion;\r
+ }\r
+\r
+ public List<Resource> getResources() {\r
+ return resources;\r
+ }\r
+\r
+ public void setResources(List<Resource> resources) {\r
+ this.resources = resources;\r
+ }\r
+ }\r
+\r
+ public static class Resource {\r
+ private String resourceName;\r
+ private String commType;\r
+ private String uri;\r
+ private List<String> operations;\r
+\r
+ public String getResourceName() {\r
+ return resourceName;\r
+ }\r
+\r
+ public void setResourceName(String resourceName) {\r
+ this.resourceName = resourceName;\r
+ }\r
+\r
+ public String getCommType() {\r
+ return commType;\r
+ }\r
+\r
+ public void setCommType(String commType) {\r
+ this.commType = commType;\r
+ }\r
+\r
+ public String getUri() {\r
+ return uri;\r
+ }\r
+\r
+ public void setUri(String uri) {\r
+ this.uri = uri;\r
+ }\r
+\r
+ public List<String> getOperations() {\r
+ return operations;\r
+ }\r
+\r
+ public void setOperations(List<String> operations) {\r
+ this.operations = operations;\r
+ }\r
+ }\r
+\r
+ public static class InterfaceDescription {\r
+ private String ipv4Addr;\r
+ private int port;\r
+\r
+ public String getIpv4Addr() {\r
+ return ipv4Addr;\r
+ }\r
+\r
+ public void setIpv4Addr(String ipv4Addr) {\r
+ this.ipv4Addr = ipv4Addr;\r
+ }\r
+\r
+ public int getPort() {\r
+ return port;\r
+ }\r
+\r
+ public void setPort(int port) {\r
+ this.port = port;\r
+ }\r
+ }\r
+}\r
+\r
--- /dev/null
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
-# Hello World Service Stub\r
+# Hello World Service\r
\r
This repository contains a Spring Boot application serving a Hello World endpoint. The application can be built and \r
-run using the provided script - ``service-stub-build-start.sh``.\r
+run using the provided script - ``hello-world-build-start.sh``.\r
\r
## Prerequisites\r
\r
Run the script:\r
\r
```bash\r
- ./service-stub-build-start.sh\r
+ ./hello-world-build-start.sh\r
```\r
\r
The script will build a Docker image and run a container with the Hello World service. After the container starts, \r
Hello World endpoint and display the response:\r
\r
```bash\r
- response=$(curl -s http://localhost:8080/helloworld/v1/sme)\r
- echo "Response from the Hello World SME endpoint:"\r
+ response=$(curl -s http://localhost:8080/helloworld/v1)\r
+ echo "Response from the Hello World endpoint:"\r
echo "$response"\r
```\r
\r
To stop and remove the Docker container:\r
\r
```bash\r
- docker stop service-stub-hello-world-test\r
- docker rm service-stub-hello-world-test\r
+ docker stop hello-world\r
+ docker rm hello-world\r
```\r
\r
## Additional Information\r
\r
-- The Hello World SME endpoint is available at http://localhost:8080/helloworld/v1/sme.\r
+- The Hello World endpoint is available at http://localhost:8080/helloworld/v1.\r
\r
print_usage
fi
-IMAGE_NAME="nonrtric-hello-world"
+IMAGE_NAME="nonrtric-sample-helloworld"
IMAGE_TAG="latest"
REPO=""
if [ $1 == "no-push" ]; then
services:
hello-world:
build:
- context: ./
+ context: ../../sample-services/hello-world
dockerfile: Dockerfile
ports:
- 8080:8080
\ No newline at end of file
# ========================LICENSE_END===================================
#
-NAME="service-stub-hello-world-test"
-IMAGE_NAME="nonrtric-hello-world"
+NAME="hello-world"
+IMAGE_NAME="nonrtric-sample-helloworld"
docker build -t $IMAGE_NAME:latest .
--- /dev/null
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
targetPort: http
protocol: TCP
name: http
- nodePort: 30951
selector:
{{- include "hello-world-chart.selectorLabels" . | nindent 4 }}
#
image:
- repository: nonrtric-hello-world
+ repository: nexus3.o-ran-sc.org:10003/nonrtric-sample-helloworld
tag: latest
service:
name: hello-world
- type: NodePort
+ type: ClusterIP
port: 8080
<parent>\r
<groupId>org.springframework.boot</groupId>\r
<artifactId>spring-boot-starter-parent</artifactId>\r
- <version>3.2.1</version>\r
+ <version>3.2.3</version>\r
</parent>\r
\r
<groupId>org.o-ran-sc.nonrtric.plt</groupId>\r
import org.springframework.boot.autoconfigure.SpringBootApplication;\r
\r
@SpringBootApplication(scanBasePackages = "org.oransc.nonrtric.sample")\r
-public class ServiceStubApplication {\r
+public class HelloWorldApplication {\r
public static void main(String[] args) {\r
- SpringApplication.run(ServiceStubApplication.class, args);\r
+ SpringApplication.run(HelloWorldApplication.class, args);\r
}\r
}\r
+++ /dev/null
-{{/*
-Expand the name of the chart.
-*/}}
-{{- define "hello-world-chart.name" -}}
-{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
-{{- end }}
-
-{{/*
-Create a default fully qualified app name.
-We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
-If release name contains chart name it will be used as a full name.
-*/}}
-{{- define "hello-world-chart.fullname" -}}
-{{- if .Values.fullnameOverride }}
-{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
-{{- else }}
-{{- $name := default .Chart.Name .Values.nameOverride }}
-{{- if contains $name .Release.Name }}
-{{- .Release.Name | trunc 63 | trimSuffix "-" }}
-{{- else }}
-{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
-{{- end }}
-{{- end }}
-{{- end }}
-
-{{/*
-Create chart name and version as used by the chart label.
-*/}}
-{{- define "hello-world-chart.chart" -}}
-{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
-{{- end }}
-
-{{/*
-Common labels
-*/}}
-{{- define "hello-world-chart.labels" -}}
-helm.sh/chart: {{ include "hello-world-chart.chart" . }}
-{{ include "hello-world-chart.selectorLabels" . }}
-{{- if .Chart.AppVersion }}
-app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
-{{- end }}
-app.kubernetes.io/managed-by: {{ .Release.Service }}
-{{- end }}
-
-{{/*
-Selector labels
-*/}}
-{{- define "hello-world-chart.selectorLabels" -}}
-app.kubernetes.io/name: {{ include "hello-world-chart.name" . }}
-app.kubernetes.io/instance: {{ .Release.Name }}
-{{- end }}
-
-{{/*
-Create the name of the service account to use
-*/}}
-{{- define "hello-world-chart.serviceAccountName" -}}
-{{- if .Values.serviceAccount.create }}
-{{- default (include "hello-world-chart.fullname" .) .Values.serviceAccount.name }}
-{{- else }}
-{{- default "default" .Values.serviceAccount.name }}
-{{- end }}
-{{- end }}