Merge "Fix participantHtml issue with multi instances in ACM"
diff --git a/participant/participant-impl/participant-impl-http/src/main/java/org/onap/policy/clamp/acm/participant/http/main/handler/AutomationCompositionElementHandler.java b/participant/participant-impl/participant-impl-http/src/main/java/org/onap/policy/clamp/acm/participant/http/main/handler/AutomationCompositionElementHandler.java
index c62216d..0568d3b 100644
--- a/participant/participant-impl/participant-impl-http/src/main/java/org/onap/policy/clamp/acm/participant/http/main/handler/AutomationCompositionElementHandler.java
+++ b/participant/participant-impl/participant-impl-http/src/main/java/org/onap/policy/clamp/acm/participant/http/main/handler/AutomationCompositionElementHandler.java
@@ -31,7 +31,8 @@
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.validation.Validation;
-import javax.validation.ValidationException;
+import javax.ws.rs.core.Response.Status;
+import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.tuple.Pair;
import org.onap.policy.clamp.acm.participant.http.main.models.ConfigRequest;
@@ -55,6 +56,7 @@
* This class handles implementation of automationCompositionElement updates.
*/
@Component
+@RequiredArgsConstructor
public class AutomationCompositionElementHandler implements AutomationCompositionElementListener, Closeable {
private static final Coder CODER = new StandardCoder();
@@ -63,22 +65,20 @@
private final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
- private final Map<ToscaConceptIdentifier, Pair<Integer, String>> restResponseMap = new ConcurrentHashMap<>();
-
@Setter
private ParticipantIntermediaryApi intermediaryApi;
+ private final AcHttpClient acHttpClient;
+
/**
* Handle a automation composition element state change.
*
* @param automationCompositionElementId the ID of the automation composition element
- * @throws PfModelException in case of a model exception
*/
@Override
- public void undeploy(UUID automationCompositionId,
- UUID automationCompositionElementId) {
- intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
- automationCompositionElementId, DeployState.UNDEPLOYED, LockState.NONE);
+ public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) {
+ intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, automationCompositionElementId,
+ DeployState.UNDEPLOYED, LockState.NONE);
}
/**
@@ -87,31 +87,36 @@
* @param automationCompositionId the automationComposition Id
* @param element the information on the automation composition element
* @param properties properties Map
+ * @throws PfModelException in case of a exception
*/
@Override
- public void deploy(UUID automationCompositionId,
- AcElementDeploy element, Map<String, Object> properties) {
+ public void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
+ throws PfModelException {
+ var configRequest = getConfigRequest(properties);
+ var restResponseMap = invokeHttpClient(configRequest);
+ var failedResponseStatus = restResponseMap.values().stream()
+ .filter(response -> !HttpStatus.valueOf(response.getKey()).is2xxSuccessful())
+ .collect(Collectors.toList());
+ if (failedResponseStatus.isEmpty()) {
+ intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
+ DeployState.DEPLOYED, LockState.LOCKED);
+ } else {
+ throw new PfModelException(Status.BAD_REQUEST, "Error on Invoking the http request: {}",
+ failedResponseStatus);
+ }
+ }
+
+ private ConfigRequest getConfigRequest(Map<String, Object> properties) throws PfModelException {
try {
var configRequest = CODER.convert(properties, ConfigRequest.class);
- var violations =
- Validation.buildDefaultValidatorFactory().getValidator().validate(configRequest);
- if (violations.isEmpty()) {
- invokeHttpClient(configRequest);
- var failedResponseStatus = restResponseMap.values().stream()
- .filter(response -> !HttpStatus.valueOf(response.getKey())
- .is2xxSuccessful()).collect(Collectors.toList());
- if (failedResponseStatus.isEmpty()) {
- intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
- DeployState.DEPLOYED, LockState.LOCKED);
- } else {
- LOGGER.error("Error on Invoking the http request: {}", failedResponseStatus);
- }
- } else {
+ var violations = Validation.buildDefaultValidatorFactory().getValidator().validate(configRequest);
+ if (!violations.isEmpty()) {
LOGGER.error("Violations found in the config request parameters: {}", violations);
- throw new ValidationException("Constraint violations in the config request");
+ throw new PfModelException(Status.BAD_REQUEST, "Constraint violations in the config request");
}
- } catch (CoderException | ValidationException | InterruptedException | ExecutionException e) {
- LOGGER.error("Error invoking the http request for the config ", e);
+ return configRequest;
+ } catch (CoderException e) {
+ throw new PfModelException(Status.BAD_REQUEST, "Error extracting ConfigRequest ", e);
}
}
@@ -120,11 +125,21 @@
*
* @param configRequest ConfigRequest
*/
- public void invokeHttpClient(ConfigRequest configRequest) throws ExecutionException, InterruptedException {
- // Invoke runnable thread to execute https requests of all config entities
- var result = executor.submit(new AcHttpClient(configRequest, restResponseMap), restResponseMap);
- if (!result.get().isEmpty()) {
- LOGGER.debug("Http Request Completed: {}", result.isDone());
+ private Map<ToscaConceptIdentifier, Pair<Integer, String>> invokeHttpClient(ConfigRequest configRequest)
+ throws PfModelException {
+ try {
+ Map<ToscaConceptIdentifier, Pair<Integer, String>> restResponseMap = new ConcurrentHashMap<>();
+ // Invoke runnable thread to execute https requests of all config entities
+ var result = executor.submit(() -> acHttpClient.run(configRequest, restResponseMap), restResponseMap);
+ if (!result.get().isEmpty()) {
+ LOGGER.debug("Http Request Completed: {}", result.isDone());
+ }
+ return restResponseMap;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new PfModelException(Status.BAD_REQUEST, "Error invoking ExecutorService ", e);
+ } catch (ExecutionException e) {
+ throw new PfModelException(Status.BAD_REQUEST, "Error invoking the http request for the config ", e);
}
}
diff --git a/participant/participant-impl/participant-impl-http/src/main/java/org/onap/policy/clamp/acm/participant/http/main/webclient/AcHttpClient.java b/participant/participant-impl/participant-impl-http/src/main/java/org/onap/policy/clamp/acm/participant/http/main/webclient/AcHttpClient.java
index 563daec..c71d73f 100644
--- a/participant/participant-impl/participant-impl-http/src/main/java/org/onap/policy/clamp/acm/participant/http/main/webclient/AcHttpClient.java
+++ b/participant/participant-impl/participant-impl-http/src/main/java/org/onap/policy/clamp/acm/participant/http/main/webclient/AcHttpClient.java
@@ -1,6 +1,6 @@
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 Nordix Foundation.
+ * 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.
@@ -35,83 +35,69 @@
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
-public class AcHttpClient implements Runnable {
+@Component
+public class AcHttpClient {
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private final ConfigRequest configRequest;
-
- private Map<ToscaConceptIdentifier, Pair<Integer, String>> responseMap;
-
- /**
- * Constructor.
- */
- public AcHttpClient(ConfigRequest configRequest, Map<ToscaConceptIdentifier, Pair<Integer, String>> responseMap) {
- this.configRequest = configRequest;
- this.responseMap = responseMap;
- }
-
/**
* Runnable to execute http requests.
*/
- @Override
- public void run() {
+ public void run(ConfigRequest configRequest, Map<ToscaConceptIdentifier, Pair<Integer, String>> responseMap) {
- var webClient = WebClient.builder()
- .baseUrl(configRequest.getBaseUrl())
- .defaultHeaders(httpHeaders -> httpHeaders.addAll(createHeaders(configRequest)))
- .build();
+ var webClient = WebClient.builder().baseUrl(configRequest.getBaseUrl())
+ .defaultHeaders(httpHeaders -> httpHeaders.addAll(createHeaders(configRequest))).build();
- for (ConfigurationEntity configurationEntity : configRequest.getConfigurationEntities()) {
+ for (var configurationEntity : configRequest.getConfigurationEntities()) {
LOGGER.info("Executing http requests for the config entity {}",
- configurationEntity.getConfigurationEntityId());
+ configurationEntity.getConfigurationEntityId());
- executeRequest(webClient, configurationEntity);
+ executeRequest(webClient, configRequest, configurationEntity, responseMap);
}
}
- private void executeRequest(WebClient client, ConfigurationEntity configurationEntity) {
+ private void executeRequest(WebClient client, ConfigRequest configRequest, ConfigurationEntity configurationEntity,
+ Map<ToscaConceptIdentifier, Pair<Integer, String>> responseMap) {
// Iterate the sequence of http requests
- for (RestParams request: configurationEntity.getRestSequence()) {
- String response = null;
+ for (var request : configurationEntity.getRestSequence()) {
try {
var httpMethod = Objects.requireNonNull(HttpMethod.resolve(request.getHttpMethod()));
var uri = createUriString(request);
LOGGER.info("Executing HTTP request: {} for the Rest request id: {}", httpMethod,
request.getRestRequestId());
- response = client.method(httpMethod)
- .uri(uri)
- .body(request.getBody() == null ? BodyInserters.empty()
- : BodyInserters.fromValue(request.getBody()))
- .exchangeToMono(clientResponse ->
- clientResponse.statusCode().value() == request.getExpectedResponse()
- ? clientResponse.bodyToMono(String.class)
- : Mono.error(new HttpWebClientException(clientResponse.statusCode().value(),
- clientResponse.bodyToMono(String.class).toString())))
- .block(Duration.ofMillis(configRequest.getUninitializedToPassiveTimeout() * 1000L));
+ var response = client.method(httpMethod).uri(uri)
+ .body(request.getBody() == null ? BodyInserters.empty()
+ : BodyInserters.fromValue(request.getBody()))
+ .exchangeToMono(
+ clientResponse -> clientResponse.statusCode().value() == request.getExpectedResponse()
+ ? clientResponse.bodyToMono(String.class)
+ : Mono.error(new HttpWebClientException(clientResponse.statusCode().value(),
+ clientResponse.bodyToMono(String.class).toString())))
+ .block(Duration.ofMillis(configRequest.getUninitializedToPassiveTimeout() * 1000L));
LOGGER.info("HTTP response for the {} request : {}", httpMethod, response);
- responseMap.put(request.getRestRequestId(), new ImmutablePair<>(request.getExpectedResponse(),
- response));
+ responseMap.put(request.getRestRequestId(),
+ new ImmutablePair<>(request.getExpectedResponse(), response));
} catch (HttpWebClientException ex) {
LOGGER.error("Error occurred on the HTTP request ", ex);
- responseMap.put(request.getRestRequestId(), new ImmutablePair<>(ex.getStatusCode().value(),
- ex.getResponseBodyAsString()));
+ responseMap.put(request.getRestRequestId(),
+ new ImmutablePair<>(ex.getStatusCode().value(), ex.getResponseBodyAsString()));
}
}
}
private HttpHeaders createHeaders(ConfigRequest request) {
var headers = new HttpHeaders();
- for (Map.Entry<String, String> entry: request.getHttpHeaders().entrySet()) {
+ for (var entry : request.getHttpHeaders().entrySet()) {
headers.add(entry.getKey(), entry.getValue());
}
return headers;
@@ -125,7 +111,7 @@
}
// Add query params if present
if (restParams.getQueryParams() != null) {
- for (Map.Entry<String, String> entry : restParams.getQueryParams().entrySet()) {
+ for (var entry : restParams.getQueryParams().entrySet()) {
uriComponentsBuilder.queryParam(entry.getKey(), entry.getValue());
}
}
diff --git a/participant/participant-impl/participant-impl-http/src/test/java/org/onap/policy/clamp/acm/participant/http/handler/AcElementHandlerTest.java b/participant/participant-impl/participant-impl-http/src/test/java/org/onap/policy/clamp/acm/participant/http/handler/AcElementHandlerTest.java
index 857490e..e48fdf9 100644
--- a/participant/participant-impl/participant-impl-http/src/test/java/org/onap/policy/clamp/acm/participant/http/handler/AcElementHandlerTest.java
+++ b/participant/participant-impl/participant-impl-http/src/test/java/org/onap/policy/clamp/acm/participant/http/handler/AcElementHandlerTest.java
@@ -20,76 +20,78 @@
package org.onap.policy.clamp.acm.participant.http.handler;
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
+import static org.mockito.ArgumentMatchers.anyMap;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.util.HashMap;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
+import java.util.Map;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mockito;
-import org.mockito.Spy;
import org.onap.policy.clamp.acm.participant.http.main.handler.AutomationCompositionElementHandler;
import org.onap.policy.clamp.acm.participant.http.main.models.ConfigRequest;
+import org.onap.policy.clamp.acm.participant.http.main.webclient.AcHttpClient;
import org.onap.policy.clamp.acm.participant.http.utils.CommonTestData;
import org.onap.policy.clamp.acm.participant.http.utils.ToscaUtils;
import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
-import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.onap.policy.clamp.models.acm.concepts.DeployState;
+import org.onap.policy.clamp.models.acm.concepts.LockState;
-@ExtendWith(SpringExtension.class)
class AcElementHandlerTest {
- @InjectMocks
- @Spy
- private AutomationCompositionElementHandler automationCompositionElementHandler =
- new AutomationCompositionElementHandler();
-
private final CommonTestData commonTestData = new CommonTestData();
-
- private static ToscaServiceTemplate serviceTemplate;
private static final String HTTP_AUTOMATION_COMPOSITION_ELEMENT =
"org.onap.domain.database.Http_PMSHMicroserviceAutomationCompositionElement";
- @BeforeAll
- static void init() {
- serviceTemplate = ToscaUtils.readAutomationCompositionFromTosca();
- }
+ @Test
+ void testUndeploy() throws IOException {
+ var instanceId = commonTestData.getAutomationCompositionId();
+ var element = commonTestData.getAutomationCompositionElement();
+ var acElementId = element.getId();
- @BeforeEach
- void startMocks() {
- automationCompositionElementHandler.setIntermediaryApi(Mockito.mock(ParticipantIntermediaryApi.class));
+ try (var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(mock(AcHttpClient.class))) {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ automationCompositionElementHandler.setIntermediaryApi(participantIntermediaryApi);
+ automationCompositionElementHandler.undeploy(instanceId, acElementId);
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(instanceId, acElementId,
+ DeployState.UNDEPLOYED, LockState.NONE);
+ }
}
@Test
- void test_automationCompositionElementStateChange() throws IOException {
- var automationCompositionId = commonTestData.getAutomationCompositionId();
+ void testDeployError() throws IOException {
+ var instanceId = commonTestData.getAutomationCompositionId();
var element = commonTestData.getAutomationCompositionElement();
- var automationCompositionElementId = element.getId();
- var config = Mockito.mock(ConfigRequest.class);
- assertDoesNotThrow(() -> automationCompositionElementHandler.invokeHttpClient(config));
-
- assertDoesNotThrow(() -> automationCompositionElementHandler.undeploy(
- automationCompositionId, automationCompositionElementId));
-
- automationCompositionElementHandler.close();
+ try (var automationCompositionElementHandler =
+ new AutomationCompositionElementHandler(mock(AcHttpClient.class))) {
+ automationCompositionElementHandler.setIntermediaryApi(mock(ParticipantIntermediaryApi.class));
+ Map<String, Object> map = new HashMap<>();
+ assertThatThrownBy(() -> automationCompositionElementHandler.deploy(instanceId, element, map))
+ .hasMessage("Constraint violations in the config request");
+ }
}
@Test
- void test_AutomationCompositionElementUpdate() throws Exception {
- doNothing().when(automationCompositionElementHandler).invokeHttpClient(any());
- var element = commonTestData.getAutomationCompositionElement();
-
+ void testDeploy() throws Exception {
+ var serviceTemplate = ToscaUtils.readAutomationCompositionFromTosca();
var nodeTemplatesMap = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates();
var map = new HashMap<>(nodeTemplatesMap.get(HTTP_AUTOMATION_COMPOSITION_ELEMENT).getProperties());
+ var element = commonTestData.getAutomationCompositionElement();
map.putAll(element.getProperties());
+ var instanceId = commonTestData.getAutomationCompositionId();
+ var acHttpClient = mock(AcHttpClient.class);
+ try (var automationCompositionElementHandler = new AutomationCompositionElementHandler(acHttpClient)) {
+ var participantIntermediaryApi = mock(ParticipantIntermediaryApi.class);
+ automationCompositionElementHandler.setIntermediaryApi(participantIntermediaryApi);
+ automationCompositionElementHandler.deploy(instanceId, element, map);
+ verify(acHttpClient).run(any(ConfigRequest.class), anyMap());
+ verify(participantIntermediaryApi).updateAutomationCompositionElementState(instanceId, element.getId(),
+ DeployState.DEPLOYED, LockState.LOCKED);
+ }
- assertDoesNotThrow(() -> automationCompositionElementHandler
- .deploy(commonTestData.getAutomationCompositionId(), element, map));
}
}
diff --git a/participant/participant-impl/participant-impl-http/src/test/java/org/onap/policy/clamp/acm/participant/http/webclient/AcHttpClientTest.java b/participant/participant-impl/participant-impl-http/src/test/java/org/onap/policy/clamp/acm/participant/http/webclient/AcHttpClientTest.java
index 3ddd7b1..d8e0c9b 100644
--- a/participant/participant-impl/participant-impl-http/src/test/java/org/onap/policy/clamp/acm/participant/http/webclient/AcHttpClientTest.java
+++ b/participant/participant-impl/participant-impl-http/src/test/java/org/onap/policy/clamp/acm/participant/http/webclient/AcHttpClientTest.java
@@ -1,6 +1,6 @@
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2022 Nordix Foundation.
+ * 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.
@@ -78,8 +78,8 @@
var configRequest =
new ConfigRequest(testMockUrl + ":" + mockServerPort, headers, List.of(configurationEntity), 10);
- var client = new AcHttpClient(configRequest, responseMap);
- assertDoesNotThrow(client::run);
+ var client = new AcHttpClient();
+ assertDoesNotThrow(() -> client.run(configRequest, responseMap));
assertThat(responseMap).hasSize(2).containsKey(commonTestData.restParamsWithGet().getRestRequestId());
var restResponseMap = responseMap.get(commonTestData.restParamsWithGet().getRestRequestId());
@@ -96,8 +96,8 @@
var configRequest =
new ConfigRequest(testMockUrl + ":" + mockServerPort, headers, List.of(configurationEntity), 10);
- var client = new AcHttpClient(configRequest, responseMap);
- assertDoesNotThrow(client::run);
+ var client = new AcHttpClient();
+ assertDoesNotThrow(() -> client.run(configRequest, responseMap));
assertThat(responseMap).hasSize(2).containsKey(commonTestData.restParamsWithGet().getRestRequestId());
var response = responseMap.get(commonTestData.restParamsWithInvalidPost().getRestRequestId());
assertThat(response.getKey()).isEqualTo(404);