Add backend implementation of enrichment api 25/4825/1
authorRehanRaza <muhammad.rehan.raza@est.tech>
Thu, 8 Oct 2020 14:12:06 +0000 (16:12 +0200)
committerRehanRaza <muhammad.rehan.raza@est.tech>
Thu, 8 Oct 2020 14:12:20 +0000 (16:12 +0200)
Change-Id: Ie85c2719dffafc96ad003c594d52a4411823b777
Issue-ID: NONRTRIC-295
Signed-off-by: RehanRaza <muhammad.rehan.raza@est.tech>
webapp-backend/pom.xml
webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/controller/EnrichmentController.java [new file with mode: 0644]
webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/eiproducerapi/EiProducerApi.java [new file with mode: 0644]
webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/eiproducerapi/EiProducerApiImpl.java [new file with mode: 0644]
webapp-backend/src/main/resources/application.properties

index e701624..95de721 100644 (file)
@@ -40,6 +40,7 @@ limitations under the License.
         <spotless-maven-plugin.version>1.18.0</spotless-maven-plugin.version>
         <jacoco-maven-plugin.version>0.8.5</jacoco-maven-plugin.version>
         <docker-maven-plugin.version>0.33.0</docker-maven-plugin.version>
+        <json.version>20190722</json.version>
         <!-- Set by Jenkins -->
         <build.number>0</build.number>
     </properties>
@@ -152,6 +153,11 @@ limitations under the License.
             <artifactId>gson</artifactId>
             <version>${immutable.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>${json.version}</version>
+        </dependency>
         <!-- Test dependencies -->
         <!-- Mockito supports development, not just testing -->
         <dependency>
diff --git a/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/controller/EnrichmentController.java b/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/controller/EnrichmentController.java
new file mode 100644 (file)
index 0000000..558923f
--- /dev/null
@@ -0,0 +1,123 @@
+/*-
+ * ========================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===================================
+ */
+package org.oransc.portal.nonrtric.controlpanel.controller;
+
+import java.lang.invoke.MethodHandles;
+import org.oransc.portal.nonrtric.controlpanel.ControlPanelConstants;
+import org.oransc.portal.nonrtric.controlpanel.eiproducerapi.EiProducerApi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * Proxies calls from the front end to the EI Producer API.
+ *
+ * If a method throws RestClientResponseException, it is handled by
+ * {@link CustomResponseEntityExceptionHandler#handleProxyMethodException(Exception, org.springframework.web.context.request.WebRequest)}
+ * which returns status 502. All other exceptions are handled by Spring which
+ * returns status 500.
+ */
+@RestController
+@RequestMapping(value = EnrichmentController.CONTROLLER_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
+public class EnrichmentController {
+
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+    // Publish paths in constants so tests are easy to write
+    public static final String CONTROLLER_PATH = ControlPanelConstants.ENDPOINT_PREFIX + "/enrichment";
+    // Endpoints
+    public static final String VERSION_METHOD = ControlPanelConstants.VERSION_METHOD;
+    public static final String EI_TYPES = "eitypes";
+    public static final String EI_PRODUCERS = "eiproducers";
+    public static final String EI_JOBS = "eijobs";
+    public static final String EI_TYPE_ID = "ei_type_id";
+    public static final String EI_PRODUCER_ID = "ei_producer_id";
+    public static final String STATUS = "status";
+
+    // Populated by the autowired constructor
+    private final EiProducerApi eiProducerApi;
+
+    @Autowired
+    public EnrichmentController(final EiProducerApi eiProducerApi) {
+        Assert.notNull(eiProducerApi, "API must not be null");
+        this.eiProducerApi = eiProducerApi;
+        logger.debug("enrichment: configured with client type {}", eiProducerApi.getClass().getName());
+    }
+
+    /*
+     * The fields are defined in the Enrichment Control Typescript interface.
+     */
+    @ApiOperation(value = "Get the EI type identifiers")
+    @GetMapping(EI_TYPES)
+    @Secured({ControlPanelConstants.ROLE_ADMIN, ControlPanelConstants.ROLE_STANDARD})
+    public ResponseEntity<String> getAllEiTypeIds() {
+        logger.debug("getAllEiTypeIds");
+        return this.eiProducerApi.getAllEiTypeIds();
+    }
+
+    @ApiOperation(value = "Get an individual EI type")
+    @GetMapping(EI_TYPES + "/{" + EI_TYPE_ID + "}")
+    @Secured({ControlPanelConstants.ROLE_ADMIN, ControlPanelConstants.ROLE_STANDARD})
+    public ResponseEntity<String> getEiType(@PathVariable(EI_TYPE_ID) String eiTypeId) {
+        logger.debug("getEiType {}", eiTypeId);
+        return this.eiProducerApi.getEiType(eiTypeId);
+    }
+
+    @ApiOperation(value = "Get the EI producer identifiers")
+    @GetMapping(EI_PRODUCERS)
+    @Secured({ControlPanelConstants.ROLE_ADMIN, ControlPanelConstants.ROLE_STANDARD})
+    public ResponseEntity<String> getAllEiProducerIds() {
+        logger.debug("getAllEiProducerIds");
+        return this.eiProducerApi.getAllEiProducerIds();
+    }
+
+    @ApiOperation(value = "Get an individual EI producer")
+    @GetMapping(EI_PRODUCERS + "/{" + EI_PRODUCER_ID + "}")
+    @Secured({ControlPanelConstants.ROLE_ADMIN, ControlPanelConstants.ROLE_STANDARD})
+    public ResponseEntity<String> getEiProducer(@PathVariable(EI_PRODUCER_ID) String eiProducerId) {
+        logger.debug("getEiProducer {}", eiProducerId);
+        return this.eiProducerApi.getEiProducer(eiProducerId);
+    }
+
+    @ApiOperation(value = "Get the EI job definitions for one EI producer")
+    @GetMapping(EI_PRODUCERS + "/{" + EI_PRODUCER_ID + "}/" + EI_JOBS)
+    @Secured({ControlPanelConstants.ROLE_ADMIN, ControlPanelConstants.ROLE_STANDARD})
+    public ResponseEntity<String> getEiJobsForOneEiProducer(@PathVariable(EI_PRODUCER_ID) String eiProducerId) {
+        logger.debug("getEiJobsForOneEiProducer {}", eiProducerId);
+        return this.eiProducerApi.getEiJobsForOneEiProducer(eiProducerId);
+    }
+
+    @ApiOperation(value = "Get the status of an EI producer")
+    @GetMapping(EI_PRODUCERS + "/{" + EI_PRODUCER_ID + "}/" + STATUS)
+    @Secured({ControlPanelConstants.ROLE_ADMIN, ControlPanelConstants.ROLE_STANDARD})
+    public ResponseEntity<String> getEiProducerStatus(@PathVariable(EI_PRODUCER_ID) String eiProducerId) {
+        logger.debug("getEiProducerStatus {}", eiProducerId);
+        return this.eiProducerApi.getEiProducerStatus(eiProducerId);
+    }
+}
\ No newline at end of file
diff --git a/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/eiproducerapi/EiProducerApi.java b/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/eiproducerapi/EiProducerApi.java
new file mode 100644 (file)
index 0000000..0e6b5c4
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * ========================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===================================
+ */
+package org.oransc.portal.nonrtric.controlpanel.eiproducerapi;
+
+import org.springframework.http.ResponseEntity;
+
+public interface EiProducerApi {
+
+    public ResponseEntity<String> getAllEiTypeIds();
+
+    public ResponseEntity<String> getEiType(String eiTypeId);
+
+    public ResponseEntity<String> getAllEiProducerIds();
+
+    public ResponseEntity<String> getEiProducer(String eiProducerId);
+
+    public ResponseEntity<String> getEiJobsForOneEiProducer(String eiProducerId);
+
+    public ResponseEntity<String> getEiProducerStatus(String eiProducerId);
+
+}
diff --git a/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/eiproducerapi/EiProducerApiImpl.java b/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/eiproducerapi/EiProducerApiImpl.java
new file mode 100644 (file)
index 0000000..ca45e27
--- /dev/null
@@ -0,0 +1,131 @@
+/*-
+ * ========================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===================================
+ */
+package org.oransc.portal.nonrtric.controlpanel.eiproducerapi;
+
+import com.google.gson.GsonBuilder;
+import java.lang.invoke.MethodHandles;
+import javax.net.ssl.SSLException;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.oransc.portal.nonrtric.controlpanel.util.AsyncRestClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
+
+@Component("EiProducerApi")
+public class EiProducerApiImpl implements EiProducerApi {
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+    private static final String EI_TYPES = "/eitypes";
+    private static final String EI_PRODUCERS = "/eiproducers";
+    private static final String EI_JOBS = "/eijobs";
+    private static final String STATUS = "/status";
+
+    private final AsyncRestClient webClient;
+
+    private static com.google.gson.Gson gson = new GsonBuilder() //
+        .serializeNulls() //
+        .create(); //
+
+    @Autowired
+    public EiProducerApiImpl(
+        @org.springframework.beans.factory.annotation.Value("${enrichmentcontroller.url.prefix}") final String urlPrefix) {
+        this(new AsyncRestClient(urlPrefix));
+        logger.debug("enrichment controller url prefix '{}'", urlPrefix);
+    }
+
+    public EiProducerApiImpl(AsyncRestClient webClient) {
+        this.webClient = webClient;
+    }
+
+    @Override
+    public ResponseEntity<String> getAllEiTypeIds() {
+        return getResponseArray(EI_TYPES);
+    }
+
+    @Override
+    public ResponseEntity<String> getEiType(String eiTypeId) {
+        return getResponseObject(EI_TYPES + "/" + eiTypeId);
+    }
+
+    @Override
+    public ResponseEntity<String> getAllEiProducerIds() {
+        return getResponseArray(EI_PRODUCERS);
+    }
+
+    @Override
+    public ResponseEntity<String> getEiProducer(String eiProducerId) {
+        return getResponseObject(EI_PRODUCERS + "/" + eiProducerId);
+    }
+
+    @Override
+    public ResponseEntity<String> getEiJobsForOneEiProducer(String eiProducerId) {
+        return getResponseArray(EI_PRODUCERS + "/" + eiProducerId + EI_JOBS);
+    }
+
+    @Override
+    public ResponseEntity<String> getEiProducerStatus(String eiProducerId) {
+        return getResponseObject(EI_PRODUCERS + "/" + eiProducerId + STATUS);
+    }
+
+    private ResponseEntity<String> getResponseArray(String url) {
+        try {
+            ResponseEntity<String> rsp = webClient.getForEntity(url).block();
+            if (!rsp.getStatusCode().is2xxSuccessful()) {
+                return rsp;
+            }
+            return new ResponseEntity<>(new JSONArray(rsp.getBody()).toString(), rsp.getStatusCode());
+        } catch (Exception e) {
+            return handleException(e);
+        }
+    }
+
+    private ResponseEntity<String> getResponseObject(String url) {
+        try {
+            ResponseEntity<String> rsp = webClient.getForEntity(url).block();
+            if (!rsp.getStatusCode().is2xxSuccessful()) {
+                return rsp;
+            }
+            return new ResponseEntity<>(new JSONObject(rsp.getBody()).toString(), rsp.getStatusCode());
+        } catch (Exception e) {
+            return handleException(e);
+        }
+    }
+
+    private ResponseEntity<String> handleException(Exception throwable) {
+        if (throwable instanceof HttpClientErrorException) {
+            HttpClientErrorException e = (HttpClientErrorException) throwable;
+            return new ResponseEntity<>(e.getMessage(), e.getStatusCode());
+        } else if (throwable instanceof HttpServerErrorException) {
+            HttpServerErrorException e = (HttpServerErrorException) throwable;
+            return new ResponseEntity<>(e.getResponseBodyAsString(), e.getStatusCode());
+        } else if (throwable instanceof SSLException) {
+            SSLException e = (SSLException) throwable;
+            return new ResponseEntity<>("Could not create WebClient " + e.getMessage(),
+                HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+        return new ResponseEntity<>(throwable.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+    }
+}
index c2d5e1a..6533651 100644 (file)
@@ -54,6 +54,10 @@ portalapi.password =
 # policycontroller.url.prefix = https://policy-agent-container:8433
 policycontroller.url.prefix = http://policy-agent-container:8081
 
+# URL for enrichment coordinator service
+# enrichmentcontroller.url.prefix = https://enrichment-service-container:8434
+enrichmentcontroller.url.prefix = http://enrichment-service-container:8082/ei-producer/v1
+
 # Mimic slow endpoints by defining sleep period, in milliseconds
 mock.config.delay = 0