From: RehanRaza Date: Thu, 8 Oct 2020 14:12:06 +0000 (+0200) Subject: Add backend implementation of enrichment api X-Git-Tag: 2.1.0~11 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=60e8bb72f91d6cc3c72b4e50124955561f73caad;hp=e35e6d8cf57b093b039f8228d9259dbd71dedb6d;p=portal%2Fnonrtric-controlpanel.git Add backend implementation of enrichment api Change-Id: Ie85c2719dffafc96ad003c594d52a4411823b777 Issue-ID: NONRTRIC-295 Signed-off-by: RehanRaza --- diff --git a/webapp-backend/pom.xml b/webapp-backend/pom.xml index e701624..95de721 100644 --- a/webapp-backend/pom.xml +++ b/webapp-backend/pom.xml @@ -40,6 +40,7 @@ limitations under the License. 1.18.0 0.8.5 0.33.0 + 20190722 0 @@ -152,6 +153,11 @@ limitations under the License. gson ${immutable.version} + + org.json + json + ${json.version} + 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 index 0000000..558923f --- /dev/null +++ b/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/controller/EnrichmentController.java @@ -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 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 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 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 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 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 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 index 0000000..0e6b5c4 --- /dev/null +++ b/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/eiproducerapi/EiProducerApi.java @@ -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 getAllEiTypeIds(); + + public ResponseEntity getEiType(String eiTypeId); + + public ResponseEntity getAllEiProducerIds(); + + public ResponseEntity getEiProducer(String eiProducerId); + + public ResponseEntity getEiJobsForOneEiProducer(String eiProducerId); + + public ResponseEntity 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 index 0000000..ca45e27 --- /dev/null +++ b/webapp-backend/src/main/java/org/oransc/portal/nonrtric/controlpanel/eiproducerapi/EiProducerApiImpl.java @@ -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 getAllEiTypeIds() { + return getResponseArray(EI_TYPES); + } + + @Override + public ResponseEntity getEiType(String eiTypeId) { + return getResponseObject(EI_TYPES + "/" + eiTypeId); + } + + @Override + public ResponseEntity getAllEiProducerIds() { + return getResponseArray(EI_PRODUCERS); + } + + @Override + public ResponseEntity getEiProducer(String eiProducerId) { + return getResponseObject(EI_PRODUCERS + "/" + eiProducerId); + } + + @Override + public ResponseEntity getEiJobsForOneEiProducer(String eiProducerId) { + return getResponseArray(EI_PRODUCERS + "/" + eiProducerId + EI_JOBS); + } + + @Override + public ResponseEntity getEiProducerStatus(String eiProducerId) { + return getResponseObject(EI_PRODUCERS + "/" + eiProducerId + STATUS); + } + + private ResponseEntity getResponseArray(String url) { + try { + ResponseEntity 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 getResponseObject(String url) { + try { + ResponseEntity 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 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); + } +} diff --git a/webapp-backend/src/main/resources/application.properties b/webapp-backend/src/main/resources/application.properties index c2d5e1a..6533651 100644 --- a/webapp-backend/src/main/resources/application.properties +++ b/webapp-backend/src/main/resources/application.properties @@ -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