diff options
Diffstat (limited to 'cps-ncmp-service/src/main')
18 files changed, 376 insertions, 269 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java index 798a280c8a..ef48c43d2a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation + * Copyright (C) 2021-2024 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,20 +21,31 @@ package org.onap.cps.ncmp.api.impl.client; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; + import com.fasterxml.jackson.databind.JsonNode; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Locale; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration.DmiProperties; -import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException; +import org.onap.cps.ncmp.api.impl.config.DmiProperties; +import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException; +import org.onap.cps.ncmp.api.impl.exception.InvalidDmiResourceUrlException; import org.onap.cps.ncmp.api.impl.operations.OperationType; -import org.springframework.http.HttpEntity; +import org.onap.cps.utils.JsonObjectMapper; import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; @Component @RequiredArgsConstructor @@ -43,8 +54,10 @@ public class DmiRestClient { private static final String HEALTH_CHECK_URL_EXTENSION = "/actuator/health"; private static final String NOT_SPECIFIED = ""; - private final RestTemplate restTemplate; + private static final String NO_AUTHORIZATION = null; + private final WebClient webClient; private final DmiProperties dmiProperties; + private final JsonObjectMapper jsonObjectMapper; /** * Sends POST operation to DMI with json body containing module references. @@ -59,14 +72,16 @@ public class DmiRestClient { final String requestBodyAsJsonString, final OperationType operationType, final String authorization) { - final var httpEntity = new HttpEntity<>(requestBodyAsJsonString, configureHttpHeaders(new HttpHeaders(), - authorization)); try { - return restTemplate.postForEntity(dmiResourceUrl, httpEntity, Object.class); - } catch (final HttpStatusCodeException httpStatusCodeException) { - final String exceptionMessage = "Unable to " + operationType.toString() + " resource data."; - throw new HttpClientRequestException(exceptionMessage, httpStatusCodeException.getResponseBodyAsString(), - httpStatusCodeException.getStatusCode().value()); + return ResponseEntity.ok(webClient.post().uri(toUri(dmiResourceUrl)) + .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization)) + .body(BodyInserters.fromValue(requestBodyAsJsonString)) + .retrieve() + .bodyToMono(Object.class) + .onErrorMap(httpError -> handleDmiClientException(httpError, operationType.getOperationName())) + .block()); + } catch (final HttpServerErrorException e) { + throw handleDmiClientException(e, operationType.getOperationName()); } } @@ -77,13 +92,14 @@ public class DmiRestClient { * @return plugin health status ("UP" is all OK, "" (not-specified) in case of any exception) */ public String getDmiHealthStatus(final String dmiPluginBaseUrl) { - final HttpEntity<Object> httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders(), null)); try { - final JsonNode responseHealthStatus = - restTemplate.getForObject(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION, - JsonNode.class, httpHeaders); + final JsonNode responseHealthStatus = webClient.get() + .uri(toUri(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION)) + .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION)) + .retrieve() + .bodyToMono(JsonNode.class).block(); return responseHealthStatus == null ? NOT_SPECIFIED : - responseHealthStatus.get("status").asText(); + responseHealthStatus.get("status").asText(); } catch (final Exception e) { log.warn("Failed to retrieve health status from {}. Error Message: {}", dmiPluginBaseUrl, e.getMessage()); return NOT_SPECIFIED; @@ -96,7 +112,33 @@ public class DmiRestClient { } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) { httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization); } - httpHeaders.setContentType(MediaType.APPLICATION_JSON); return httpHeaders; } + + private static URI toUri(final String dmiResourceUrl) { + try { + return new URI(dmiResourceUrl); + } catch (final URISyntaxException e) { + throw new InvalidDmiResourceUrlException(dmiResourceUrl, BAD_REQUEST.value()); + } + } + + private DmiClientRequestException handleDmiClientException(final Throwable e, final String operationType) { + final String exceptionMessage = "Unable to " + operationType + " resource data."; + if (e instanceof WebClientResponseException wcre) { + if (wcre.getStatusCode().isSameCodeAs(HttpStatus.REQUEST_TIMEOUT)) { + throw new DmiClientRequestException(wcre.getStatusCode().value(), wcre.getMessage(), + jsonObjectMapper.asJsonString(wcre.getResponseBodyAsString()), DMI_SERVICE_NOT_RESPONDING); + } + throw new DmiClientRequestException(wcre.getStatusCode().value(), wcre.getMessage(), + jsonObjectMapper.asJsonString(wcre.getResponseBodyAsString()), UNABLE_TO_READ_RESOURCE_DATA); + + } + if (e instanceof HttpServerErrorException httpServerErrorException) { + throw new DmiClientRequestException(httpServerErrorException.getStatusCode().value(), exceptionMessage, + httpServerErrorException.getResponseBodyAsString(), DMI_SERVICE_NOT_RESPONDING); + } + throw new DmiClientRequestException(INTERNAL_SERVER_ERROR.value(), exceptionMessage, e.getMessage(), + UNKNOWN_ERROR); + } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiProperties.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiProperties.java new file mode 100644 index 0000000000..5453efecd0 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiProperties.java @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.config; + +import lombok.AccessLevel; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Getter +@Component +public class DmiProperties { + @Value("${ncmp.dmi.auth.username}") + private String authUsername; + @Value("${ncmp.dmi.auth.password}") + private String authPassword; + @Getter(AccessLevel.NONE) + @Value("${ncmp.dmi.api.base-path}") + private String dmiBasePath; + @Value("${ncmp.dmi.auth.enabled}") + private boolean dmiBasicAuthEnabled; + + /** + * Removes both leading and trailing slashes if they are present. + * + * @return dmi base path without any slashes ("/") + */ + public String getDmiBasePath() { + if (dmiBasePath.startsWith("/")) { + dmiBasePath = dmiBasePath.substring(1); + } + if (dmiBasePath.endsWith("/")) { + dmiBasePath = dmiBasePath.substring(0, dmiBasePath.length() - 1); + } + return dmiBasePath; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java new file mode 100644 index 0000000000..2e84f7f69f --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java @@ -0,0 +1,70 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.config; + +import io.netty.channel.ChannelOption; +import io.netty.handler.timeout.ReadTimeoutHandler; +import io.netty.handler.timeout.WriteTimeoutHandler; +import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.netty.http.client.HttpClient; +import reactor.netty.resources.ConnectionProvider; + +@Configuration +@RequiredArgsConstructor +public class DmiWebClientConfiguration { + + private final HttpClientConfiguration httpClientConfiguration; + + /** + * Configures and create a WebClient bean that triggers an initialization (warmup) of the host name resolver and + * loads the necessary native libraries to avoid the extra time needed to load resources for first request. + * + * @return a WebClient instance. + */ + @Bean + public WebClient webClient() { + final ConnectionProvider dmiWebClientConnectionProvider = ConnectionProvider.create( + "dmiWebClientConnectionPool", httpClientConfiguration.getMaximumConnectionsTotal()); + + final HttpClient httpClient = HttpClient.create(dmiWebClientConnectionProvider) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, + httpClientConfiguration.getConnectionTimeoutInSeconds() * 1000) + .doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler( + httpClientConfiguration.getReadTimeoutInSeconds(), TimeUnit.SECONDS)) + .addHandlerLast(new WriteTimeoutHandler( + httpClientConfiguration.getWriteTimeoutInSeconds(), TimeUnit.SECONDS))); + httpClient.warmup().block(); + return WebClient.builder() + .defaultHeaders(header -> header.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)) + .defaultHeaders(header -> header.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)) + .clientConnector(new ReactorClientHttpConnector(httpClient)) + .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize( + httpClientConfiguration.getMaximumInMemorySizeInMegabytes() * 1024 * 1024)) + .build(); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java index d547e31c68..d2521d9d1e 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation. + * Copyright (C) 2023-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,38 +20,19 @@ package org.onap.cps.ncmp.api.impl.config; -import java.time.Duration; -import java.time.temporal.ChronoUnit; import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.convert.DurationUnit; +import org.springframework.stereotype.Component; @Getter @Setter -@ConfigurationProperties(prefix = "ncmp.dmi.httpclient", ignoreUnknownFields = true) +@Component +@ConfigurationProperties(prefix = "ncmp.dmi.httpclient") public class HttpClientConfiguration { - - /** - * The maximum time to establish a connection. - */ - @DurationUnit(ChronoUnit.SECONDS) - private Duration connectionTimeoutInSeconds = Duration.ofSeconds(180); - - /** - * The maximum number of open connections per route. - */ - private int maximumConnectionsPerRoute = 50; - - /** - * The maximum total number of open connections. - */ - private int maximumConnectionsTotal = maximumConnectionsPerRoute * 2; - - /** - * The duration after which idle connections are evicted. - */ - @DurationUnit(ChronoUnit.SECONDS) - private Duration idleConnectionEvictionThresholdInSeconds = Duration.ofSeconds(5); - + private Integer maximumConnectionsTotal = 100; + private Integer connectionTimeoutInSeconds = 30; + private Integer readTimeoutInSeconds = 30; + private Integer writeTimeoutInSeconds = 30; + private Integer maximumInMemorySizeInMegabytes = 1; } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java deleted file mode 100644 index c6ff116a7f..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config; - -import java.util.Arrays; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.apache.hc.client5.http.config.ConnectionConfig; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; -import org.apache.hc.core5.util.TimeValue; -import org.apache.hc.core5.util.Timeout; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; -import org.springframework.http.MediaType; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; - -@Configuration -@EnableConfigurationProperties(HttpClientConfiguration.class) -@RequiredArgsConstructor(access = AccessLevel.PROTECTED) -public class NcmpConfiguration { - - @Getter - @Component - public static class DmiProperties { - @Value("${ncmp.dmi.auth.username}") - private String authUsername; - @Value("${ncmp.dmi.auth.password}") - private String authPassword; - @Value("${ncmp.dmi.api.base-path}") - private String dmiBasePath; - @Value("${ncmp.dmi.auth.enabled}") - private boolean dmiBasicAuthEnabled; - } - - /** - * Rest template bean. - * - * @param restTemplateBuilder the rest template builder - * @param httpClientConfiguration the http client configuration - * @return rest template instance - */ - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public static RestTemplate restTemplate(final RestTemplateBuilder restTemplateBuilder, - final HttpClientConfiguration httpClientConfiguration) { - - final ConnectionConfig connectionConfig = ConnectionConfig.copy(ConnectionConfig.DEFAULT) - .setConnectTimeout(Timeout.of(httpClientConfiguration.getConnectionTimeoutInSeconds())) - .build(); - - final PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() - .setDefaultConnectionConfig(connectionConfig) - .setMaxConnTotal(httpClientConfiguration.getMaximumConnectionsTotal()) - .setMaxConnPerRoute(httpClientConfiguration.getMaximumConnectionsPerRoute()) - .build(); - - final CloseableHttpClient httpClient = HttpClients.custom() - .setConnectionManager(connectionManager) - .evictExpiredConnections() - .evictIdleConnections( - TimeValue.of(httpClientConfiguration.getIdleConnectionEvictionThresholdInSeconds())) - .build(); - - final ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); - - final RestTemplate restTemplate = restTemplateBuilder - .requestFactory(() -> requestFactory) - .setConnectTimeout(httpClientConfiguration.getConnectionTimeoutInSeconds()) - .build(); - - setRestTemplateMessageConverters(restTemplate); - return restTemplate; - } - - private static void setRestTemplateMessageConverters(final RestTemplate restTemplate) { - final MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = - new MappingJackson2HttpMessageConverter(); - mappingJackson2HttpMessageConverter.setSupportedMediaTypes( - Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); - restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java index fb89aae3f8..3e072b0f91 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionDmiOutEventConsumer.java @@ -51,7 +51,7 @@ public class CmNotificationSubscriptionDmiOutEventConsumer { * * @param cmNotificationSubscriptionDmiOutEventConsumerRecord the event to be consumed */ - @KafkaListener(topics = "${app.ncmp.avc.subscription-response-topic}", + @KafkaListener(topics = "${app.ncmp.avc.cm-subscription-dmi-out}", containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") public void consumeCmNotificationSubscriptionDmiOutEvent( final ConsumerRecord<String, CloudEvent> cmNotificationSubscriptionDmiOutEventConsumerRecord) { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java index 70135b3079..2c544b7b6a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/consumer/CmNotificationSubscriptionNcmpInEventConsumer.java @@ -28,7 +28,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.onap.cps.ncmp.api.impl.events.cmsubscription.service.CmNotificationSubscriptionHandlerService; import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.client_to_ncmp.CmNotificationSubscriptionNcmpInEvent; -import org.springframework.beans.factory.annotation.Value; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; @@ -39,15 +38,12 @@ public class CmNotificationSubscriptionNcmpInEventConsumer { private final CmNotificationSubscriptionHandlerService cmNotificationSubscriptionHandlerService; - @Value("${notification.enabled:true}") - private boolean notificationFeatureEnabled; - /** * Consume the specified event. * * @param subscriptionEventConsumerRecord the event to be consumed */ - @KafkaListener(topics = "${app.ncmp.avc.subscription-topic}", + @KafkaListener(topics = "${app.ncmp.avc.cm-subscription-ncmp-in}", containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") public void consumeSubscriptionEvent(final ConsumerRecord<String, CloudEvent> subscriptionEventConsumerRecord) { final CloudEvent cloudEvent = subscriptionEventConsumerRecord.value(); @@ -60,7 +56,7 @@ public class CmNotificationSubscriptionNcmpInEventConsumer { if ("subscriptionCreateRequest".equals(cloudEvent.getType())) { log.info("Subscription for source {} with subscription id {} ...", cloudEvent.getSource(), subscriptionId); cmNotificationSubscriptionHandlerService.processSubscriptionCreateRequest( - cmNotificationSubscriptionNcmpInEvent); + cmNotificationSubscriptionNcmpInEvent); } } }
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java index 9fbe26848f..3273c556c6 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionDmiInEventProducer.java @@ -25,7 +25,6 @@ import io.cloudevents.core.builder.CloudEventBuilder; import java.net.URI; import java.util.UUID; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.onap.cps.events.EventsPublisher; import org.onap.cps.ncmp.events.cmnotificationsubscription_merge1_0_0.ncmp_to_dmi.CmNotificationSubscriptionDmiInEvent; import org.onap.cps.utils.JsonObjectMapper; @@ -34,7 +33,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; @Component -@Slf4j @RequiredArgsConstructor @ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) public class CmNotificationSubscriptionDmiInEventProducer { @@ -42,7 +40,7 @@ public class CmNotificationSubscriptionDmiInEventProducer { private final EventsPublisher<CloudEvent> eventsPublisher; private final JsonObjectMapper jsonObjectMapper; - @Value("${app.ncmp.avc.subscription-forward-topic-prefix}") + @Value("${app.ncmp.avc.cm-subscription-dmi-in}") private String cmNotificationSubscriptionDmiInEventTopic; /** @@ -65,9 +63,10 @@ public class CmNotificationSubscriptionDmiInEventProducer { final String dmiPluginName, final String eventType, final CmNotificationSubscriptionDmiInEvent cmNotificationSubscriptionDmiInEvent) { return CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withType(eventType) - .withSource(URI.create("NCMP")).withDataSchema(URI.create("org.onap.ncmp.dmi.cm.subscription:1.0.0")) - .withExtension("correlationid", subscriptionId.concat("#").concat(dmiPluginName)) - .withData(jsonObjectMapper.asJsonBytes(cmNotificationSubscriptionDmiInEvent)).build(); + .withSource(URI.create("NCMP")) + .withDataSchema(URI.create("org.onap.ncmp.dmi.cm.subscription:1.0.0")) + .withExtension("correlationid", subscriptionId.concat("#").concat(dmiPluginName)) + .withData(jsonObjectMapper.asJsonBytes(cmNotificationSubscriptionDmiInEvent)).build(); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java index ac5de07f0a..ed7ed2a0ba 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/cmsubscription/producer/CmNotificationSubscriptionNcmpOutEventProducer.java @@ -48,7 +48,7 @@ import org.springframework.stereotype.Component; @ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) public class CmNotificationSubscriptionNcmpOutEventProducer { - @Value("${app.ncmp.avc.subscription-outcome-topic}") + @Value("${app.ncmp.avc.cm-subscription-ncmp-out}") private String cmNotificationSubscriptionNcmpOutEventTopic; @Value("${ncmp.timers.subscription-forwarding.dmi-response-timeout-ms}") diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java new file mode 100644 index 0000000000..ab0fa68938 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java @@ -0,0 +1,54 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.exception; + +import lombok.Getter; +import org.onap.cps.ncmp.api.NcmpResponseStatus; + +/** + * Http Client Request exception from dmi service. + */ +@Getter +public class DmiClientRequestException extends NcmpException { + + private static final long serialVersionUID = 6659897770659834797L; + final NcmpResponseStatus ncmpResponseStatus; + final String message; + final String responseBodyAsString; + final int httpStatusCode; + + /** + * Constructor to form exception for dmi service response. + * + * @param httpStatusCode http response code from the client + * @param message response message from the client + * @param responseBodyAsString response body from the client + * @param ncmpResponseStatus ncmp status message and code + */ + public DmiClientRequestException(final int httpStatusCode, final String message, final String responseBodyAsString, + final NcmpResponseStatus ncmpResponseStatus) { + super(message, responseBodyAsString); + this.httpStatusCode = httpStatusCode; + this.message = message; + this.responseBodyAsString = responseBodyAsString; + this.ncmpResponseStatus = ncmpResponseStatus; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/HttpClientRequestException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDmiResourceUrlException.java index 9d307e5d2e..270988b63b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/HttpClientRequestException.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/InvalidDmiResourceUrlException.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2024 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,24 +22,16 @@ package org.onap.cps.ncmp.api.impl.exception; import lombok.Getter; -/** - * Http Client Request exception for passthrough scenarios. - */ @Getter -public class HttpClientRequestException extends NcmpException { +public class InvalidDmiResourceUrlException extends RuntimeException { + + private static final long serialVersionUID = 2928476384584894968L; - private static final long serialVersionUID = 6659897770659834797L; + private static final String INVALID_DMI_URL = "Invalid dmi resource url"; final Integer httpStatus; - /** - * Constructor to form exception for passthrough scenarios. - * - * @param message message details from NCMP - * @param details response body from the client available as details - * @param httpStatus http status code from the client - */ - public HttpClientRequestException(final String message, final String details, final Integer httpStatus) { - super(message, details); + public InvalidDmiResourceUrlException(final String details, final Integer httpStatus) { + super(String.format(INVALID_DMI_URL + ": %s", details)); this.httpStatus = httpStatus; } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java index 2e66ac0bf1..7baac34b1f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperation.java @@ -40,7 +40,7 @@ public class DmiDataOperation { private String options; private String resourceIdentifier; - private final List<CmHandle> cmHandles = new ArrayList<>(); + private final List<DmiOperationCmHandle> cmHandles = new ArrayList<>(); /** * Create and initialise a (outgoing) DMI data operation. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java index a9ec1241bc..1e92bfe425 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java @@ -21,8 +21,6 @@ package org.onap.cps.ncmp.api.impl.operations; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA; import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING; import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ; @@ -35,8 +33,8 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NcmpResponseStatus; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration; -import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException; +import org.onap.cps.ncmp.api.impl.config.DmiProperties; +import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException; import org.onap.cps.ncmp.api.impl.inventory.CmHandleState; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder; @@ -61,7 +59,7 @@ public class DmiDataOperations extends DmiOperations { public DmiDataOperations(final InventoryPersistence inventoryPersistence, final JsonObjectMapper jsonObjectMapper, - final NcmpConfiguration.DmiProperties dmiProperties, + final DmiProperties dmiProperties, final DmiRestClient dmiRestClient, final DmiServiceUrlBuilder dmiServiceUrlBuilder) { super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder); @@ -90,9 +88,14 @@ public class DmiDataOperations extends DmiOperations { final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle); - final String dmiResourceDataUrl = getDmiRequestUrl(cmResourceAddress.datastoreName(), - cmResourceAddress.cmHandleId(), cmResourceAddress.resourceIdentifier(), optionsParamInQuery, - topicParamInQuery, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); + + final MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap( + cmResourceAddress.resourceIdentifier(), optionsParamInQuery, + topicParamInQuery, yangModelCmHandle.getModuleSetTag()); + final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(cmResourceAddress.datastoreName(), + yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmResourceAddress.cmHandleId()); + final String dmiResourceDataUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap); + return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, authorization); } @@ -111,9 +114,13 @@ public class DmiDataOperations extends DmiOperations { final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle); - final String dmiResourceDataUrl = getDmiRequestUrl(dataStoreName, cmHandleId, "/", - null, null, - yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); + + final MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap("/", null, + null, yangModelCmHandle.getModuleSetTag()); + final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(dataStoreName, + yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmHandleId); + final String dmiResourceDataUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap); + final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, null); @@ -168,9 +175,13 @@ public class DmiDataOperations extends DmiOperations { final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); final String jsonRequestBody = getDmiRequestBody(operationType, null, requestData, dataType, yangModelCmHandle); - final String dmiUrl = getDmiRequestUrl(PASSTHROUGH_RUNNING.getDatastoreName(), cmHandleId, resourceId, - null, null, - yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); + + final MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap(resourceId, null, + null, yangModelCmHandle.getModuleSetTag()); + final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(PASSTHROUGH_RUNNING.getDatastoreName(), + yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmHandleId); + final String dmiUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap); + final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType, authorization); @@ -195,16 +206,23 @@ public class DmiDataOperations extends DmiOperations { return jsonObjectMapper.asJsonString(dmiRequestBody); } - private String getDmiRequestUrl(final String dataStoreName, - final String cmHandleId, - final String resourceId, - final String optionsParamInQuery, - final String topicParamInQuery, - final String dmiServiceName) { - return dmiServiceUrlBuilder.getDmiDatastoreUrl( - dmiServiceUrlBuilder.populateQueryParams(resourceId, optionsParamInQuery, - topicParamInQuery), dmiServiceUrlBuilder.populateUriVariables(dataStoreName, dmiServiceName, - cmHandleId)); + private String getDmiRequestUrl(final MultiValueMap<String, String> uriQueryParamsMap, + final Map<String, Object> uriVariableParamsMap) { + return dmiServiceUrlBuilder.getDmiDatastoreUrl(uriQueryParamsMap, uriVariableParamsMap); + } + + private MultiValueMap<String, String> getUriQueryParamsMap(final String resourceId, + final String optionsParamInQuery, + final String topicParamInQuery, + final String moduleSetTagParamInQuery) { + return dmiServiceUrlBuilder.populateQueryParams(resourceId, optionsParamInQuery, + topicParamInQuery, moduleSetTagParamInQuery); + } + + private Map<String, Object> getUriVariableParamsMap(final String dataStoreName, + final String dmiServiceName, + final String cmHandleId) { + return dmiServiceUrlBuilder.populateUriVariables(dataStoreName, dmiServiceName, cmHandleId); } private String getDmiServiceDataOperationRequestUrl(final String dmiServiceName, @@ -226,7 +244,7 @@ public class DmiDataOperations extends DmiOperations { } private static Set<String> getDistinctCmHandleIdsFromDataOperationRequest(final DataOperationRequest - dataOperationRequest) { + dataOperationRequest) { return dataOperationRequest.getDataOperationDefinitions().stream() .flatMap(dataOperationDefinition -> dataOperationDefinition.getCmHandleIds().stream()).collect(Collectors.toSet()); @@ -235,7 +253,7 @@ public class DmiDataOperations extends DmiOperations { private void buildDataOperationRequestUrlAndSendToDmiService(final String topicParamInQuery, final String requestId, final Map<String, List<DmiDataOperation>> - groupsOutPerDmiServiceName, + groupsOutPerDmiServiceName, final String authorization) { groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> { @@ -256,36 +274,29 @@ public class DmiDataOperations extends DmiOperations { try { dmiRestClient.postOperationWithJsonData(dataOperationResourceUrl, dmiDataOperationRequestAsJsonString, READ, authorization); - } catch (final Exception exception) { - handleTaskCompletionException(exception, dataOperationResourceUrl, dmiDataOperationRequestBodies); + } catch (final DmiClientRequestException e) { + handleTaskCompletionException(e, dataOperationResourceUrl, dmiDataOperationRequestBodies); } } - private void handleTaskCompletionException(final Throwable throwable, + private void handleTaskCompletionException(final DmiClientRequestException dmiClientRequestException, final String dataOperationResourceUrl, final List<DmiDataOperation> dmiDataOperationRequestBodies) { - if (throwable != null) { - final MultiValueMap<String, String> dataOperationResourceUrlParameters = - UriComponentsBuilder.fromUriString(dataOperationResourceUrl).build().getQueryParams(); - final String topicName = dataOperationResourceUrlParameters.get("topic").get(0); - final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0); - - final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>> - cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>(); - - dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> { - final List<String> cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream() - .map(CmHandle::getId).toList(); - if (throwable.getCause() instanceof HttpClientRequestException) { - cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody, - Map.of(UNABLE_TO_READ_RESOURCE_DATA, cmHandleIds)); - } else { - cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody, - Map.of(DMI_SERVICE_NOT_RESPONDING, cmHandleIds)); - } - }); - ResourceDataOperationRequestUtils.publishErrorMessageToClientTopic(topicName, requestId, - cmHandleIdsPerResponseCodesPerOperation); - } + final MultiValueMap<String, String> dataOperationResourceUrlParameters = + UriComponentsBuilder.fromUriString(dataOperationResourceUrl).build().getQueryParams(); + final String topicName = dataOperationResourceUrlParameters.get("topic").get(0); + final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0); + + final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>> + cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>(); + + dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> { + final List<String> cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream() + .map(DmiOperationCmHandle::getId).toList(); + cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody, + Map.of(dmiClientRequestException.getNcmpResponseStatus(), cmHandleIds)); + }); + ResourceDataOperationRequestUtils.publishErrorMessageToClientTopic(topicName, requestId, + cmHandleIdsPerResponseCodesPerOperation); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java index 798f6de810..d54dcb8deb 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java @@ -34,7 +34,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration; +import org.onap.cps.ncmp.api.impl.config.DmiProperties; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; @@ -57,7 +57,7 @@ public class DmiModelOperations extends DmiOperations { */ public DmiModelOperations(final InventoryPersistence inventoryPersistence, final JsonObjectMapper jsonObjectMapper, - final NcmpConfiguration.DmiProperties dmiProperties, + final DmiProperties dmiProperties, final DmiRestClient dmiRestClient, final DmiServiceUrlBuilder dmiServiceUrlBuilder) { super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/CmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperationCmHandle.java index 618da74543..1bf2b77dcc 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/CmHandle.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperationCmHandle.java @@ -29,14 +29,21 @@ import lombok.Getter; @JsonInclude(JsonInclude.Include.NON_NULL) @Getter @Builder -public class CmHandle { +public class DmiOperationCmHandle { private String id; @JsonProperty("cmHandleProperties") private Map<String, String> dmiProperties; + private String moduleSetTag; - public static CmHandle buildCmHandleWithProperties(final String cmHandleId, - final Map<String, String> dmiProperties) { - return CmHandle.builder().id(cmHandleId).dmiProperties(dmiProperties).build(); + /** + * Builds Dmi Operation Cm Handle object with all its associated properties. + */ + public static DmiOperationCmHandle buildDmiOperationCmHandle(final String cmHandleId, + final Map<String, String> dmiProperties, + final String moduleSetTag) { + return DmiOperationCmHandle.builder().id(cmHandleId) + .dmiProperties(dmiProperties).moduleSetTag(moduleSetTag) + .build(); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java index c8d73eac63..c195ab3096 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation + * Copyright (C) 2021-2024 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ package org.onap.cps.ncmp.api.impl.operations; import lombok.RequiredArgsConstructor; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration; +import org.onap.cps.ncmp.api.impl.config.DmiProperties; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder; import org.onap.cps.utils.JsonObjectMapper; @@ -35,7 +35,7 @@ public class DmiOperations { protected final InventoryPersistence inventoryPersistence; protected final JsonObjectMapper jsonObjectMapper; - protected final NcmpConfiguration.DmiProperties dmiProperties; + protected final DmiProperties dmiProperties; protected final DmiRestClient dmiRestClient; protected final DmiServiceUrlBuilder dmiServiceUrlBuilder; @@ -44,6 +44,4 @@ public class DmiOperations { .pathSegment("{resourceName}") .buildAndExpand(dmiServiceName, dmiProperties.getDmiBasePath(), cmHandle, resourceName).toUriString(); } - - } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java index 04acaa5e9b..9234d3c2f1 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java @@ -20,12 +20,14 @@ package org.onap.cps.ncmp.api.impl.utils; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import lombok.RequiredArgsConstructor; import org.apache.logging.log4j.util.Strings; import org.apache.logging.log4j.util.TriConsumer; -import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration; +import org.onap.cps.ncmp.api.impl.config.DmiProperties; import org.onap.cps.spi.utils.CpsValidator; import org.springframework.stereotype.Component; import org.springframework.util.LinkedMultiValueMap; @@ -35,8 +37,7 @@ import org.springframework.web.util.UriComponentsBuilder; @Component @RequiredArgsConstructor public class DmiServiceUrlBuilder { - - private final NcmpConfiguration.DmiProperties dmiProperties; + private final DmiProperties dmiProperties; private final CpsValidator cpsValidator; /** @@ -133,20 +134,24 @@ public class DmiServiceUrlBuilder { * This method is used to populate map from query params. * * @param resourceId unique id of response for valid topic - * @param optionsParamInQuery options into url param - * @param topicParamInQuery topic into url param + * @param optionsParamInQuery options as provided by client + * @param topicParamInQuery topic as provided by client + * @param moduleSetTag module set tag associated with the given cm handle * @return all valid query params as map */ public MultiValueMap<String, String> populateQueryParams(final String resourceId, final String optionsParamInQuery, - final String topicParamInQuery) { + final String topicParamInQuery, + final String moduleSetTag) { final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>(); - getQueryParamConsumer().accept("resourceIdentifier", - resourceId, queryParams); + getQueryParamConsumer().accept("resourceIdentifier", resourceId, queryParams); getQueryParamConsumer().accept("options", optionsParamInQuery, queryParams); if (Strings.isNotEmpty(topicParamInQuery)) { getQueryParamConsumer().accept("topic", topicParamInQuery, queryParams); } + if (Strings.isNotEmpty(moduleSetTag)) { + getQueryParamConsumer().accept("moduleSetTag", moduleSetTag, queryParams); + } return queryParams; } @@ -168,7 +173,7 @@ public class DmiServiceUrlBuilder { private TriConsumer<String, String, MultiValueMap<String, String>> getQueryParamConsumer() { return (paramName, paramValue, paramMap) -> { if (Strings.isNotEmpty(paramValue)) { - paramMap.add(paramName, paramValue); + paramMap.add(paramName, URLEncoder.encode(paramValue, StandardCharsets.UTF_8)); } }; } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java index 4b016b37d1..dc4108cac0 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/data/operation/ResourceDataOperationRequestUtils.java @@ -39,8 +39,8 @@ import lombok.extern.slf4j.Slf4j; import org.onap.cps.events.EventsPublisher; import org.onap.cps.ncmp.api.NcmpResponseStatus; import org.onap.cps.ncmp.api.impl.inventory.CmHandleState; -import org.onap.cps.ncmp.api.impl.operations.CmHandle; import org.onap.cps.ncmp.api.impl.operations.DmiDataOperation; +import org.onap.cps.ncmp.api.impl.operations.DmiOperationCmHandle; import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer; import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; @@ -81,6 +81,8 @@ public class ResourceDataOperationRequestUtils { final Map<String, String> dmiServiceNamesPerCmHandleId = getDmiServiceNamesPerCmHandleId(dmiPropertiesPerCmHandleIdPerServiceName); + final Map<String, String> moduleSetTagPerCmHandle = getModuleSetTagPerCmHandleId(yangModelCmHandles); + for (final DataOperationDefinition dataOperationDefinitionIn : dataOperationRequestIn.getDataOperationDefinitions()) { final List<String> nonExistingCmHandleIds = new ArrayList<>(); @@ -97,9 +99,10 @@ public class ResourceDataOperationRequestUtils { } else { final DmiDataOperation dmiBatchOperationOut = getOrAddDmiBatchOperation(dmiServiceName, dataOperationDefinitionIn, dmiDataOperationsOutPerDmiServiceName); - final CmHandle cmHandle = CmHandle.buildCmHandleWithProperties(cmHandleId, - cmHandleIdProperties); - dmiBatchOperationOut.getCmHandles().add(cmHandle); + final DmiOperationCmHandle dmiOperationCmHandle = DmiOperationCmHandle + .buildDmiOperationCmHandle(cmHandleId, cmHandleIdProperties, + moduleSetTagPerCmHandle.get(cmHandleId)); + dmiBatchOperationOut.getCmHandles().add(dmiOperationCmHandle); } } } @@ -114,6 +117,14 @@ public class ResourceDataOperationRequestUtils { return dmiDataOperationsOutPerDmiServiceName; } + private static Map<String, String> getModuleSetTagPerCmHandleId( + final Collection<YangModelCmHandle> yangModelCmHandles) { + final Map<String, String> moduleSetTagPerCmHandle = new HashMap<>(yangModelCmHandles.size()); + yangModelCmHandles.forEach(yangModelCmHandle -> + moduleSetTagPerCmHandle.put(yangModelCmHandle.getId(), yangModelCmHandle.getModuleSetTag())); + return moduleSetTagPerCmHandle; + } + /** * Handles the async task completion for an entire data, publishing errors to client topic on task failure. * |