From b5aa1b04fe2cf730c434e3d5d103b3ab357f2292 Mon Sep 17 00:00:00 2001 From: PatrikBuhr Date: Fri, 9 Oct 2020 14:17:49 +0200 Subject: [PATCH] AsyncRestClient reuse of SSL context Uplift from PMS to avoid reading certs from file every time a REST client is created. Change-Id: If5ba864077425cf10ae244e4f0fa6eab5fa2968f Issue-ID: NONRTRIC-173 Signed-off-by: PatrikBuhr --- .../java/org/oransc/enrichment/BeanFactory.java | 2 +- .../oransc/enrichment/clients/AsyncRestClient.java | 113 ++----------- .../enrichment/clients/AsyncRestClientFactory.java | 179 +++++++++++++++++++++ .../enrichment/clients/ProducerCallbacks.java | 15 +- .../oransc/enrichment/clients/ProducerJobInfo.java | 8 +- .../configuration/ApplicationConfig.java | 8 +- .../enrichment/controllers/ErrorResponse.java | 8 +- .../enrichment/controllers/StatusController.java | 21 +-- .../enrichment/controllers/VoidResponse.java | 8 +- .../controllers/consumer/ConsumerConsts.java | 8 +- .../controllers/consumer/ConsumerController.java | 8 +- .../controllers/consumer/ConsumerEiJobInfo.java | 8 +- .../controllers/consumer/ConsumerEiTypeInfo.java | 8 +- .../controllers/producer/ProducerConsts.java | 8 +- .../controllers/producer/ProducerController.java | 8 +- .../controllers/producer/ProducerEiTypeInfo.java | 8 +- .../producer/ProducerRegistrationInfo.java | 8 +- .../enrichment/tasks/ProducerSupervision.java | 36 ++--- .../org/oransc/enrichment/ApplicationTest.java | 103 ++++++------ .../oransc/enrichment/MockEnrichmentService.java | 8 +- .../enrichment/clients/AsyncRestClientTest.java | 8 +- .../controller/ProducerSimulatorController.java | 8 +- 22 files changed, 344 insertions(+), 245 deletions(-) create mode 100644 enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/AsyncRestClientFactory.java diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/BeanFactory.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/BeanFactory.java index 9e2142e6..ce419562 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/BeanFactory.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/BeanFactory.java @@ -78,7 +78,7 @@ class BeanFactory { @Bean public ProducerCallbacks getProducerCallbacks() { - return new ProducerCallbacks(); + return new ProducerCallbacks(this.applicationConfig); } private static Connector getHttpConnector(int httpPort) { diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/AsyncRestClient.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/AsyncRestClient.java index 2782f94a..76da6246 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/AsyncRestClient.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/AsyncRestClient.java @@ -2,7 +2,7 @@ * ========================LICENSE_START================================= * O-RAN-SC * %% - * Copyright (C) 2019 Nordix Foundation + * 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. @@ -22,36 +22,18 @@ package org.oransc.enrichment.clients; import io.netty.channel.ChannelOption; import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.handler.timeout.WriteTimeoutHandler; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; import java.lang.invoke.MethodHandles; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Collections; -import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; -import javax.net.ssl.KeyManagerFactory; - -import org.oransc.enrichment.configuration.WebClientConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.lang.Nullable; -import org.springframework.util.ResourceUtils; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec; @@ -66,22 +48,25 @@ import reactor.netty.tcp.TcpClient; * Generic reactive REST client. */ public class AsyncRestClient { + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private WebClient webClient = null; private final String baseUrl; private static final AtomicInteger sequenceNumber = new AtomicInteger(); - private final WebClientConfig clientConfig; - static KeyStore clientTrustStore = null; - private boolean sslEnabled = true; + private final SslContext sslContext; + /** + * Note that only http (not https) will work when this constructor is used. + * + * @param baseUrl + */ public AsyncRestClient(String baseUrl) { this(baseUrl, null); - this.sslEnabled = false; } - public AsyncRestClient(String baseUrl, WebClientConfig config) { + public AsyncRestClient(String baseUrl, SslContext sslContext) { this.baseUrl = baseUrl; - this.clientConfig = config; + this.sslContext = sslContext; } public Mono> postForEntity(String uri, @Nullable String body) { @@ -185,10 +170,14 @@ public class AsyncRestClient { final Class clazz = String.class; return request.retrieve() // .toEntity(clazz) // - .doOnNext(entity -> logger.trace("{} Received: {}", traceTag, entity.getBody())) // + .doOnNext(entity -> logReceivedData(traceTag, entity)) // .doOnError(throwable -> onHttpError(traceTag, throwable)); } + private void logReceivedData(Object traceTag, ResponseEntity entity) { + logger.trace("{} Received: {} {}", traceTag, entity.getBody(), entity.getHeaders().getContentType()); + } + private static Object createTraceTag() { return sequenceNumber.incrementAndGet(); } @@ -211,65 +200,6 @@ public class AsyncRestClient { } } - private boolean isCertificateEntry(KeyStore trustStore, String alias) { - try { - return trustStore.isCertificateEntry(alias); - } catch (KeyStoreException e) { - logger.error("Error reading truststore {}", e.getMessage()); - return false; - } - } - - private Certificate getCertificate(KeyStore trustStore, String alias) { - try { - return trustStore.getCertificate(alias); - } catch (KeyStoreException e) { - logger.error("Error reading truststore {}", e.getMessage()); - return null; - } - } - - private static synchronized KeyStore getTrustStore(String trustStorePath, String trustStorePass) - throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException { - if (clientTrustStore == null) { - KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); - store.load(new FileInputStream(ResourceUtils.getFile(trustStorePath)), trustStorePass.toCharArray()); - clientTrustStore = store; - } - return clientTrustStore; - } - - private SslContext createSslContextRejectingUntrustedPeers(String trustStorePath, String trustStorePass, - KeyManagerFactory keyManager) - throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException { - - final KeyStore trustStore = getTrustStore(trustStorePath, trustStorePass); - List certificateList = Collections.list(trustStore.aliases()).stream() // - .filter(alias -> isCertificateEntry(trustStore, alias)) // - .map(alias -> getCertificate(trustStore, alias)) // - .collect(Collectors.toList()); - final X509Certificate[] certificates = certificateList.toArray(new X509Certificate[certificateList.size()]); - - return SslContextBuilder.forClient() // - .keyManager(keyManager) // - .trustManager(certificates) // - .build(); - } - - private SslContext createSslContext(KeyManagerFactory keyManager) - throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { - if (this.clientConfig.isTrustStoreUsed()) { - return createSslContextRejectingUntrustedPeers(this.clientConfig.trustStore(), - this.clientConfig.trustStorePassword(), keyManager); - } else { - // Trust anyone - return SslContextBuilder.forClient() // - .keyManager(keyManager) // - .trustManager(InsecureTrustManagerFactory.INSTANCE) // - .build(); - } - } - private TcpClient createTcpClientSecure(SslContext sslContext) { return TcpClient.create(ConnectionProvider.newConnection()) // .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) // @@ -305,18 +235,7 @@ public class AsyncRestClient { private Mono getWebClient() { if (this.webClient == null) { try { - if (this.sslEnabled) { - final KeyManagerFactory keyManager = - KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - final KeyStore keyStore = KeyStore.getInstance(this.clientConfig.keyStoreType()); - final String keyStoreFile = this.clientConfig.keyStore(); - final String keyStorePassword = this.clientConfig.keyStorePassword(); - final String keyPassword = this.clientConfig.keyPassword(); - try (final InputStream inputStream = new FileInputStream(keyStoreFile)) { - keyStore.load(inputStream, keyStorePassword.toCharArray()); - } - keyManager.init(keyStore, keyPassword.toCharArray()); - SslContext sslContext = createSslContext(keyManager); + if (this.sslContext != null) { TcpClient tcpClient = createTcpClientSecure(sslContext); this.webClient = createWebClient(this.baseUrl, tcpClient); } else { diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/AsyncRestClientFactory.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/AsyncRestClientFactory.java new file mode 100644 index 00000000..07f23e9e --- /dev/null +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/AsyncRestClientFactory.java @@ -0,0 +1,179 @@ +/*- + * ========================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.enrichment.clients; + +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.invoke.MethodHandles; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import javax.net.ssl.KeyManagerFactory; + +import org.oransc.enrichment.configuration.WebClientConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ResourceUtils; + +/** + * Factory for a generic reactive REST client. + */ +public class AsyncRestClientFactory { + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private final SslContextFactory sslContextFactory; + + public AsyncRestClientFactory(WebClientConfig clientConfig) { + if (clientConfig != null) { + this.sslContextFactory = new CachingSslContextFactory(clientConfig); + } else { + this.sslContextFactory = null; + } + } + + public AsyncRestClient createRestClient(String baseUrl) { + if (this.sslContextFactory != null) { + try { + return new AsyncRestClient(baseUrl, this.sslContextFactory.createSslContext()); + } catch (Exception e) { + String exceptionString = e.toString(); + logger.error("Could not init SSL context, reason: {}", exceptionString); + } + } + return new AsyncRestClient(baseUrl); + } + + private class SslContextFactory { + private final WebClientConfig clientConfig; + + public SslContextFactory(WebClientConfig clientConfig) { + this.clientConfig = clientConfig; + } + + public SslContext createSslContext() throws UnrecoverableKeyException, NoSuchAlgorithmException, + CertificateException, KeyStoreException, IOException { + return this.createSslContext(createKeyManager()); + } + + private SslContext createSslContext(KeyManagerFactory keyManager) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { + if (this.clientConfig.isTrustStoreUsed()) { + return createSslContextRejectingUntrustedPeers(this.clientConfig.trustStore(), + this.clientConfig.trustStorePassword(), keyManager); + } else { + // Trust anyone + return SslContextBuilder.forClient() // + .keyManager(keyManager) // + .trustManager(InsecureTrustManagerFactory.INSTANCE) // + .build(); + } + } + + private SslContext createSslContextRejectingUntrustedPeers(String trustStorePath, String trustStorePass, + KeyManagerFactory keyManager) + throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException { + + final KeyStore trustStore = getTrustStore(trustStorePath, trustStorePass); + List certificateList = Collections.list(trustStore.aliases()).stream() // + .filter(alias -> isCertificateEntry(trustStore, alias)) // + .map(alias -> getCertificate(trustStore, alias)) // + .collect(Collectors.toList()); + final X509Certificate[] certificates = certificateList.toArray(new X509Certificate[certificateList.size()]); + + return SslContextBuilder.forClient() // + .keyManager(keyManager) // + .trustManager(certificates) // + .build(); + } + + private boolean isCertificateEntry(KeyStore trustStore, String alias) { + try { + return trustStore.isCertificateEntry(alias); + } catch (KeyStoreException e) { + logger.error("Error reading truststore {}", e.getMessage()); + return false; + } + } + + private Certificate getCertificate(KeyStore trustStore, String alias) { + try { + return trustStore.getCertificate(alias); + } catch (KeyStoreException e) { + logger.error("Error reading truststore {}", e.getMessage()); + return null; + } + } + + private KeyManagerFactory createKeyManager() throws NoSuchAlgorithmException, CertificateException, IOException, + UnrecoverableKeyException, KeyStoreException { + final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + final KeyStore keyStore = KeyStore.getInstance(this.clientConfig.keyStoreType()); + final String keyStoreFile = this.clientConfig.keyStore(); + final String keyStorePassword = this.clientConfig.keyStorePassword(); + final String keyPassword = this.clientConfig.keyPassword(); + try (final InputStream inputStream = new FileInputStream(keyStoreFile)) { + keyStore.load(inputStream, keyStorePassword.toCharArray()); + } + keyManager.init(keyStore, keyPassword.toCharArray()); + return keyManager; + } + + private synchronized KeyStore getTrustStore(String trustStorePath, String trustStorePass) + throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException { + + KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); + store.load(new FileInputStream(ResourceUtils.getFile(trustStorePath)), trustStorePass.toCharArray()); + return store; + } + } + + public class CachingSslContextFactory extends SslContextFactory { + private SslContext cachedContext = null; + + public CachingSslContextFactory(WebClientConfig clientConfig) { + super(clientConfig); + } + + @Override + public SslContext createSslContext() throws UnrecoverableKeyException, NoSuchAlgorithmException, + CertificateException, KeyStoreException, IOException { + if (this.cachedContext == null) { + this.cachedContext = super.createSslContext(); + } + return this.cachedContext; + + } + } + +} diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/ProducerCallbacks.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/ProducerCallbacks.java index 7f28a12b..9b238654 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/ProducerCallbacks.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/ProducerCallbacks.java @@ -30,7 +30,6 @@ import org.oransc.enrichment.repository.EiJob; import org.oransc.enrichment.repository.EiProducer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -46,11 +45,14 @@ public class ProducerCallbacks { .serializeNulls() // .create(); // - @Autowired - ApplicationConfig applicationConfig; + private final AsyncRestClient restClient; + + public ProducerCallbacks(ApplicationConfig config) { + AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config.getWebClientConfig()); + this.restClient = restClientFactory.createRestClient(""); + } public void notifyProducersJobDeleted(EiJob eiJob) { - AsyncRestClient restClient = restClient(); ProducerJobInfo request = new ProducerJobInfo(eiJob); String body = gson.toJson(request); for (EiProducer producer : eiJob.type().getProducers()) { @@ -81,7 +83,6 @@ public class ProducerCallbacks { * @return the body of the response from the REST call */ public Mono notifyProducerJobStarted(EiProducer producer, EiJob eiJob) { - AsyncRestClient restClient = restClient(); ProducerJobInfo request = new ProducerJobInfo(eiJob); String body = gson.toJson(request); @@ -93,8 +94,4 @@ public class ProducerCallbacks { }); } - private AsyncRestClient restClient() { - return new AsyncRestClient("", this.applicationConfig.getWebClientConfig()); - } - } diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/ProducerJobInfo.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/ProducerJobInfo.java index 164159b3..ada16e2f 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/ProducerJobInfo.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/clients/ProducerJobInfo.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/configuration/ApplicationConfig.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/configuration/ApplicationConfig.java index 225b83a5..2d4087fa 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/configuration/ApplicationConfig.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/configuration/ApplicationConfig.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/ErrorResponse.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/ErrorResponse.java index 4e68c1a9..28c40bf6 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/ErrorResponse.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/ErrorResponse.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/StatusController.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/StatusController.java index a210aa59..42ab7cb8 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/StatusController.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/StatusController.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 @@ -20,6 +20,9 @@ package org.oransc.enrichment.controllers; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; + import io.swagger.annotations.Api; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -31,16 +34,13 @@ import org.immutables.gson.Gson; import org.oransc.enrichment.repository.EiJobs; import org.oransc.enrichment.repository.EiProducers; import org.oransc.enrichment.repository.EiTypes; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.gson.annotations.SerializedName; @RestController("StatusController") @Api(tags = "Service status") @@ -88,9 +88,10 @@ public class StatusController { @GetMapping(path = "/status", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Returns status and statistics of this service") - @ApiResponses(value = { // + @ApiResponses( + value = { // @ApiResponse(code = 200, message = "Service is living", response = StatusInfo.class) // - }) + }) public Mono> getStatus() { StatusInfo info = new StatusInfo("hunky dory", this.eiProducers, this.eiTypes, this.eiJobs); return Mono.just(new ResponseEntity<>(info, HttpStatus.OK)); diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/VoidResponse.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/VoidResponse.java index 1933c2b9..80b6a80b 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/VoidResponse.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/VoidResponse.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerConsts.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerConsts.java index dcddef38..a8e88d8b 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerConsts.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerConsts.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerController.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerController.java index 288421a1..f4c69f09 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerController.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerController.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerEiJobInfo.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerEiJobInfo.java index 3111d103..47abcbb7 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerEiJobInfo.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerEiJobInfo.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerEiTypeInfo.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerEiTypeInfo.java index 0d041152..3a2ab41c 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerEiTypeInfo.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/consumer/ConsumerEiTypeInfo.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerConsts.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerConsts.java index 9e56197f..9722594f 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerConsts.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerConsts.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerController.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerController.java index 8adff419..d67b8ed4 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerController.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerController.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerEiTypeInfo.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerEiTypeInfo.java index 9a821619..f13f9813 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerEiTypeInfo.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerEiTypeInfo.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerRegistrationInfo.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerRegistrationInfo.java index 19bb541e..859443d6 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerRegistrationInfo.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/producer/ProducerRegistrationInfo.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/tasks/ProducerSupervision.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/tasks/ProducerSupervision.java index 3b62fa74..f239a487 100644 --- a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/tasks/ProducerSupervision.java +++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/tasks/ProducerSupervision.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 @@ -21,6 +21,7 @@ package org.oransc.enrichment.tasks; import org.oransc.enrichment.clients.AsyncRestClient; +import org.oransc.enrichment.clients.AsyncRestClientFactory; import org.oransc.enrichment.configuration.ApplicationConfig; import org.oransc.enrichment.repository.EiJobs; import org.oransc.enrichment.repository.EiProducer; @@ -45,17 +46,20 @@ import reactor.core.publisher.Mono; public class ProducerSupervision { private static final Logger logger = LoggerFactory.getLogger(ProducerSupervision.class); - @Autowired - ApplicationConfig applicationConfig; - - @Autowired - EiProducers eiProducers; - - @Autowired - EiJobs eiJobs; + private final EiProducers eiProducers; + private final EiJobs eiJobs; + private final EiTypes eiTypes; + private final AsyncRestClient restClient; @Autowired - EiTypes eiTypes; + public ProducerSupervision(ApplicationConfig applicationConfig, EiProducers eiProducers, EiJobs eiJobs, + EiTypes eiTypes) { + AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(applicationConfig.getWebClientConfig()); + this.restClient = restClientFactory.createRestClient(""); + this.eiJobs = eiJobs; + this.eiProducers = eiProducers; + this.eiTypes = eiTypes; + } @Scheduled(fixedRate = 1000 * 60 * 5) public void checkAllProducers() { @@ -69,7 +73,7 @@ public class ProducerSupervision { } private Mono checkOneProducer(EiProducer producer) { - return restClient().get(producer.getProducerSupervisionCallbackUrl()) // + return restClient.get(producer.getProducerSupervisionCallbackUrl()) // .onErrorResume(throwable -> { handleNonRespondingProducer(throwable, producer); return Mono.empty(); @@ -91,8 +95,4 @@ public class ProducerSupervision { producer.setAliveStatus(true); } - private AsyncRestClient restClient() { - return new AsyncRestClient("", this.applicationConfig.getWebClientConfig()); - } - } diff --git a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/ApplicationTest.java b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/ApplicationTest.java index d8a0b32e..236ed3ea 100644 --- a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/ApplicationTest.java +++ b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/ApplicationTest.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 @@ -42,6 +42,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.oransc.enrichment.clients.AsyncRestClient; +import org.oransc.enrichment.clients.AsyncRestClientFactory; import org.oransc.enrichment.clients.ProducerJobInfo; import org.oransc.enrichment.configuration.ApplicationConfig; import org.oransc.enrichment.configuration.ImmutableWebClientConfig; @@ -82,9 +83,10 @@ import reactor.test.StepVerifier; @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@TestPropertySource(properties = { // +@TestPropertySource( + properties = { // "server.ssl.key-store=./config/keystore.jks", // - "app.webclient.trust-store=./config/truststore.jks" }) + "app.webclient.trust-store=./config/truststore.jks"}) class ApplicationTest { private final String EI_TYPE_ID = "typeId"; private final String EI_PRODUCER_ID = "producerId"; @@ -112,8 +114,8 @@ class ApplicationTest { ProducerSupervision producerSupervision; private static Gson gson = new GsonBuilder() // - .serializeNulls() // - .create(); // + .serializeNulls() // + .create(); // /** * Overrides the BeanFactory. @@ -283,8 +285,8 @@ class ApplicationTest { String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId"; // The element with name "property1" is mandatory in the schema - ConsumerEiJobInfo jobInfo = new ConsumerEiJobInfo(jsonObject("{ \"XXstring\" : \"value\" }"), "owner", - "targetUri"); + ConsumerEiJobInfo jobInfo = + new ConsumerEiJobInfo(jsonObject("{ \"XXstring\" : \"value\" }"), "owner", "targetUri"); String body = gson.toJson(jobInfo); testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "Json validation failure"); @@ -328,7 +330,7 @@ class ApplicationTest { String url = ConsumerConsts.API_ROOT + "/eitypes/typeId2/eijobs/jobId"; String body = gson.toJson(eiJobInfo()); testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, - "Not allowed to change type for existing EI job"); + "Not allowed to change type for existing EI job"); } @Test @@ -447,7 +449,7 @@ class ApplicationTest { } private void assertProducerOpState(String producerId, - ProducerStatusInfo.OperationalState expectedOperationalState) { + ProducerStatusInfo.OperationalState expectedOperationalState) { String statusUrl = ProducerConsts.API_ROOT + "/eiproducers/" + producerId + "/status"; ResponseEntity resp = restClient().getForEntity(statusUrl).block(); ProducerStatusInfo statusInfo = gson.fromJson(resp.getBody(), ProducerStatusInfo.class); @@ -484,28 +486,28 @@ class ApplicationTest { } ProducerEiTypeRegistrationInfo producerEiTypeRegistrationInfo(String typeId) - throws JsonMappingException, JsonProcessingException { + throws JsonMappingException, JsonProcessingException { return new ProducerEiTypeRegistrationInfo(jsonSchemaObject(), typeId); } ProducerRegistrationInfo producerEiRegistratioInfoRejecting(String typeId) - throws JsonMappingException, JsonProcessingException { + throws JsonMappingException, JsonProcessingException { Collection types = new ArrayList<>(); types.add(producerEiTypeRegistrationInfo(typeId)); return new ProducerRegistrationInfo(types, // - baseUrl() + ProducerSimulatorController.JOB_CREATED_ERROR_URL, - baseUrl() + ProducerSimulatorController.JOB_DELETED_ERROR_URL, - baseUrl() + ProducerSimulatorController.SUPERVISION_ERROR_URL); + baseUrl() + ProducerSimulatorController.JOB_CREATED_ERROR_URL, + baseUrl() + ProducerSimulatorController.JOB_DELETED_ERROR_URL, + baseUrl() + ProducerSimulatorController.SUPERVISION_ERROR_URL); } ProducerRegistrationInfo producerEiRegistratioInfo(String typeId) - throws JsonMappingException, JsonProcessingException { + throws JsonMappingException, JsonProcessingException { Collection types = new ArrayList<>(); types.add(producerEiTypeRegistrationInfo(typeId)); return new ProducerRegistrationInfo(types, // - baseUrl() + ProducerSimulatorController.JOB_CREATED_URL, - baseUrl() + ProducerSimulatorController.JOB_DELETED_URL, - baseUrl() + ProducerSimulatorController.SUPERVISION_URL); + baseUrl() + ProducerSimulatorController.JOB_CREATED_URL, + baseUrl() + ProducerSimulatorController.JOB_DELETED_URL, + baseUrl() + ProducerSimulatorController.SUPERVISION_URL); } ConsumerEiJobInfo eiJobInfo() throws JsonMappingException, JsonProcessingException { @@ -523,17 +525,17 @@ class ApplicationTest { Object jsonSchemaObject() { // a json schema with one mandatory property named "string" String schemaStr = "{" // - + "\"$schema\": \"http://json-schema.org/draft-04/schema#\"," // - + "\"type\": \"object\"," // - + "\"properties\": {" // - + EI_JOB_PROPERTY + " : {" // - + " \"type\": \"string\"" // - + " }" // - + "}," // - + "\"required\": [" // - + EI_JOB_PROPERTY // - + "]" // - + "}"; // + + "\"$schema\": \"http://json-schema.org/draft-04/schema#\"," // + + "\"type\": \"object\"," // + + "\"properties\": {" // + + EI_JOB_PROPERTY + " : {" // + + " \"type\": \"string\"" // + + " }" // + + "}," // + + "\"required\": [" // + + EI_JOB_PROPERTY // + + "]" // + + "}"; // return jsonObject(schemaStr); } @@ -542,7 +544,7 @@ class ApplicationTest { } private EiJob putEiJob(String eiTypeId, String jobId) - throws JsonMappingException, JsonProcessingException, ServiceException { + throws JsonMappingException, JsonProcessingException, ServiceException { String url = ConsumerConsts.API_ROOT + "/eitypes/" + eiTypeId + "/eijobs/" + jobId; String body = gson.toJson(eiJobInfo()); @@ -552,7 +554,7 @@ class ApplicationTest { } private EiType putEiProducerWithOneTypeRejecting(String producerId, String eiTypeId) - throws JsonMappingException, JsonProcessingException, ServiceException { + throws JsonMappingException, JsonProcessingException, ServiceException { String url = ProducerConsts.API_ROOT + "/eiproducers/" + producerId; String body = gson.toJson(producerEiRegistratioInfoRejecting(eiTypeId)); @@ -561,7 +563,7 @@ class ApplicationTest { } private EiType putEiProducerWithOneType(String producerId, String eiTypeId) - throws JsonMappingException, JsonProcessingException, ServiceException { + throws JsonMappingException, JsonProcessingException, ServiceException { String url = ProducerConsts.API_ROOT + "/eiproducers/" + producerId; String body = gson.toJson(producerEiRegistratioInfo(eiTypeId)); @@ -576,16 +578,17 @@ class ApplicationTest { private AsyncRestClient restClient(boolean useTrustValidation) { WebClientConfig config = this.applicationConfig.getWebClientConfig(); config = ImmutableWebClientConfig.builder() // - .keyStoreType(config.keyStoreType()) // - .keyStorePassword(config.keyStorePassword()) // - .keyStore(config.keyStore()) // - .keyPassword(config.keyPassword()) // - .isTrustStoreUsed(useTrustValidation) // - .trustStore(config.trustStore()) // - .trustStorePassword(config.trustStorePassword()) // - .build(); + .keyStoreType(config.keyStoreType()) // + .keyStorePassword(config.keyStorePassword()) // + .keyStore(config.keyStore()) // + .keyPassword(config.keyPassword()) // + .isTrustStoreUsed(useTrustValidation) // + .trustStore(config.trustStore()) // + .trustStorePassword(config.trustStorePassword()) // + .build(); - return new AsyncRestClient(baseUrl(), config); + AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config); + return restClientFactory.createRestClient(baseUrl()); } private AsyncRestClient restClient() { @@ -597,16 +600,16 @@ class ApplicationTest { } private void testErrorCode(Mono request, HttpStatus expStatus, String responseContains, - boolean expectApplicationProblemJsonMediaType) { + boolean expectApplicationProblemJsonMediaType) { StepVerifier.create(request) // - .expectSubscription() // - .expectErrorMatches( - t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType)) // - .verify(); + .expectSubscription() // + .expectErrorMatches( + t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType)) // + .verify(); } private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains, - boolean expectApplicationProblemJsonMediaType) { + boolean expectApplicationProblemJsonMediaType) { assertTrue(throwable instanceof WebClientResponseException); WebClientResponseException responseException = (WebClientResponseException) throwable; assertThat(responseException.getStatusCode()).isEqualTo(expStatus); diff --git a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/MockEnrichmentService.java b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/MockEnrichmentService.java index fa110445..d51007b5 100644 --- a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/MockEnrichmentService.java +++ b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/MockEnrichmentService.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/clients/AsyncRestClientTest.java b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/clients/AsyncRestClientTest.java index e2273cfa..f879c7be 100644 --- a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/clients/AsyncRestClientTest.java +++ b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/clients/AsyncRestClientTest.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 diff --git a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/controller/ProducerSimulatorController.java b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/controller/ProducerSimulatorController.java index 479c1b2d..c4651961 100644 --- a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/controller/ProducerSimulatorController.java +++ b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/controller/ProducerSimulatorController.java @@ -1,9 +1,9 @@ /*- * ========================LICENSE_START================================= - * ONAP : ccsdk oran - * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. - * ====================================================================== + * 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 -- 2.16.6