diff --git a/multiapps-controller-client/src/main/java/module-info.java b/multiapps-controller-client/src/main/java/module-info.java index fb725acb67..aead31816c 100644 --- a/multiapps-controller-client/src/main/java/module-info.java +++ b/multiapps-controller-client/src/main/java/module-info.java @@ -14,6 +14,9 @@ requires org.cloudfoundry.multiapps.common; requires org.slf4j; requires spring.core; + requires spring.webflux; + requires reactor.core; + requires org.reactivestreams; requires static com.fasterxml.jackson.annotation; requires static java.compiler; diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/ResilientCloudControllerClient.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/ResilientCloudControllerClient.java index 887f238594..9d8e8164e8 100644 --- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/ResilientCloudControllerClient.java +++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/ResilientCloudControllerClient.java @@ -12,7 +12,6 @@ import org.cloudfoundry.client.lib.ApplicationServicesUpdateCallback; import org.cloudfoundry.client.lib.CloudControllerClient; import org.cloudfoundry.client.lib.CloudControllerClientImpl; -import org.cloudfoundry.client.lib.RestLogCallback; import org.cloudfoundry.client.lib.StartingInfo; import org.cloudfoundry.client.lib.UploadStatusCallback; import org.cloudfoundry.client.lib.domain.ApplicationLog; @@ -42,7 +41,6 @@ import org.cloudfoundry.multiapps.controller.client.util.ResilientCloudOperationExecutor; import org.springframework.http.HttpStatus; import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.web.client.ResponseErrorHandler; public class ResilientCloudControllerClient implements CloudControllerClient { @@ -569,21 +567,6 @@ public void logout() { executeWithRetry(delegate::logout); } - @Override - public void registerRestLogListener(RestLogCallback callBack) { - executeWithRetry(() -> delegate.registerRestLogListener(callBack)); - } - - @Override - public void setResponseErrorHandler(ResponseErrorHandler errorHandler) { - executeWithRetry(() -> delegate.setResponseErrorHandler(errorHandler)); - } - - @Override - public void unRegisterRestLogListener(RestLogCallback callBack) { - executeWithRetry(() -> delegate.unRegisterRestLogListener(callBack)); - } - @Override public void uploadApplication(String applicationName, String file) { executeWithRetry(() -> { diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/uaa/UAAClient.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/uaa/UAAClient.java index b4b328191b..d99811e606 100644 --- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/uaa/UAAClient.java +++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/uaa/UAAClient.java @@ -5,30 +5,32 @@ import java.util.Map; import org.cloudfoundry.client.lib.util.JsonUtil; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; public class UAAClient { private static final String TOKEN_KEY_ENDPOINT = "/token_key"; protected final URL uaaUrl; - protected final RestTemplate restTemplate; + protected final WebClient webClient; - protected UAAClient(URL uaaUrl, RestTemplate restTemplate) { + protected UAAClient(URL uaaUrl, WebClient webClient) { this.uaaUrl = uaaUrl; - this.restTemplate = restTemplate; + this.webClient = webClient; } public Map readTokenKey() { String tokenKeyURL = uaaUrl.toString() + TOKEN_KEY_ENDPOINT; - ResponseEntity tokenKeyResponse = restTemplate.getForEntity(tokenKeyURL, String.class); - if (!tokenKeyResponse.hasBody()) { - throw new IllegalStateException(MessageFormat.format("Invalid response returned from /token_key: {0}", - tokenKeyResponse.getBody())); + String tokenKeyResponse = webClient.get() + .uri(tokenKeyURL) + .retrieve() + .bodyToMono(String.class) + .block(); + if (tokenKeyResponse == null) { + throw new IllegalStateException(MessageFormat.format("Invalid response returned from /token_key: {0}", tokenKeyResponse)); } - return JsonUtil.convertJsonToMap(tokenKeyResponse.getBody()); + return JsonUtil.convertJsonToMap(tokenKeyResponse); } public URL getUaaUrl() { diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/uaa/UAAClientFactory.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/uaa/UAAClientFactory.java index 5ce59d72c8..2808436ff7 100644 --- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/uaa/UAAClientFactory.java +++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/uaa/UAAClientFactory.java @@ -7,7 +7,7 @@ public class UAAClientFactory { public UAAClient createClient(URL uaaUrl) { - return new UAAClient(uaaUrl, new RestUtil().createRestTemplate(null, false)); + return new UAAClient(uaaUrl, new RestUtil().createWebClient(false)); } } diff --git a/multiapps-controller-core/src/main/java/module-info.java b/multiapps-controller-core/src/main/java/module-info.java index ac9e1d3b7a..589563a408 100644 --- a/multiapps-controller-core/src/main/java/module-info.java +++ b/multiapps-controller-core/src/main/java/module-info.java @@ -72,12 +72,14 @@ requires org.slf4j; requires org.yaml.snakeyaml; requires quartz; + requires reactor.core; requires spring.beans; requires spring.context; requires spring.core; requires spring.security.core; requires spring.security.jwt; requires spring.web; + requires spring.webflux; requires static java.compiler; requires static org.immutables.value; diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudFoundryClientFactory.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudFoundryClientFactory.java index 31487ba7d4..a9afcd995f 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudFoundryClientFactory.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudFoundryClientFactory.java @@ -1,6 +1,7 @@ package org.cloudfoundry.multiapps.controller.core.cf; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.UUID; import javax.inject.Inject; @@ -15,8 +16,7 @@ import org.cloudfoundry.client.lib.rest.ImmutableCloudControllerRestClientFactory; import org.cloudfoundry.multiapps.controller.client.ResilientCloudControllerClient; import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; @Named public class CloudFoundryClientFactory extends ClientFactory { @@ -45,18 +45,18 @@ private ImmutableCloudControllerRestClientFactory createClientFactory(Applicatio @Override protected CloudControllerClient createClient(CloudCredentials credentials) { OAuthClient oAuthClient = oAuthClientFactory.createOAuthClient(); + List exchangeFilters = getExchangeFiltersList(null, null); CloudControllerRestClient controllerClient = clientFactory.createClient(configuration.getControllerUrl(), credentials, null, - oAuthClient); - addTaggingInterceptor(controllerClient.getRestTemplate()); + oAuthClient, exchangeFilters); return new ResilientCloudControllerClient(controllerClient); } @Override protected CloudControllerClient createClient(CloudCredentials credentials, String org, String space) { OAuthClient oAuthClient = oAuthClientFactory.createOAuthClient(); + List exchangeFilters = getExchangeFiltersList(org, space); CloudControllerRestClient controllerClient = clientFactory.createClient(configuration.getControllerUrl(), credentials, org, space, - oAuthClient); - addTaggingInterceptor(controllerClient.getRestTemplate(), org, space); + oAuthClient, exchangeFilters); return new ResilientCloudControllerClient(controllerClient); } @@ -64,26 +64,16 @@ protected CloudControllerClient createClient(CloudCredentials credentials, Strin protected CloudControllerClient createClient(CloudCredentials credentials, String spaceId) { CloudSpace target = computeTarget(credentials, spaceId); OAuthClient oAuthClient = oAuthClientFactory.createOAuthClient(); + List exchangeFilters = getExchangeFiltersList(target.getOrganization() + .getName(), + target.getName()); CloudControllerRestClient controllerClient = clientFactory.createClient(configuration.getControllerUrl(), credentials, target, - oAuthClient); - addTaggingInterceptor(controllerClient.getRestTemplate(), target.getOrganization() - .getName(), - target.getName()); + oAuthClient, exchangeFilters); return new ResilientCloudControllerClient(controllerClient); } - private void addTaggingInterceptor(RestTemplate template) { - addTaggingInterceptor(template, null, null); - } - - private void addTaggingInterceptor(RestTemplate template, String org, String space) { - if (template.getInterceptors() - .isEmpty()) { - template.setInterceptors(new ArrayList<>()); - } - ClientHttpRequestInterceptor requestInterceptor = new TaggingRequestInterceptor(configuration.getVersion(), org, space); - template.getInterceptors() - .add(requestInterceptor); + private List getExchangeFiltersList(String org, String space) { + return List.of(new TaggingRequestFilterFunction(configuration.getVersion(), org, space)); } protected CloudSpace computeTarget(CloudCredentials credentials, String spaceId) { diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientExtended.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientExtended.java index c6ef262f9c..cdb86a5e1d 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientExtended.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientExtended.java @@ -10,15 +10,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; public class OAuthClientExtended extends OAuthClient { private static final Logger LOGGER = LoggerFactory.getLogger(OAuthClientExtended.class); private final TokenService tokenService; - public OAuthClientExtended(URL authorizationUrl, RestTemplate restTemplate, TokenService tokenService) { - super(authorizationUrl, restTemplate); + public OAuthClientExtended(URL authorizationUrl, WebClient webClient, TokenService tokenService) { + super(authorizationUrl, webClient); this.tokenService = tokenService; } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientFactory.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientFactory.java index 963748dffd..753a392631 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientFactory.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/OAuthClientFactory.java @@ -8,7 +8,7 @@ import org.cloudfoundry.multiapps.controller.client.uaa.UAAClient; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; @Named public class OAuthClientFactory { @@ -22,12 +22,12 @@ public class OAuthClientFactory { private ApplicationConfiguration configuration; public OAuthClient createOAuthClient() { - RestTemplate restTemplate = createRestTemplate(); - return new OAuthClientExtended(uaaClient.getUaaUrl(), restTemplate, tokenService); + WebClient webClient = createWebClient(); + return new OAuthClientExtended(uaaClient.getUaaUrl(), webClient, tokenService); } - private RestTemplate createRestTemplate() { - return restUtil.createRestTemplate(null, configuration.shouldSkipSslValidation()); + private WebClient createWebClient() { + return restUtil.createWebClient(configuration.shouldSkipSslValidation()); } } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestInterceptor.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestFilterFunction.java similarity index 62% rename from multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestInterceptor.java rename to multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestFilterFunction.java index f052b18fd0..f4fac4ba1c 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestInterceptor.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestFilterFunction.java @@ -1,14 +1,14 @@ package org.cloudfoundry.multiapps.controller.core.cf; -import java.io.IOException; - import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.ExchangeFunction; + +import reactor.core.publisher.Mono; -class TaggingRequestInterceptor implements ClientHttpRequestInterceptor { +class TaggingRequestFilterFunction implements ExchangeFilterFunction { public static final String TAG_HEADER_SPACE_NAME = "source-space"; public static final String TAG_HEADER_ORG_NAME = "source-org"; @@ -17,11 +17,11 @@ class TaggingRequestInterceptor implements ClientHttpRequestInterceptor { private final String orgHeaderValue; private final String spaceHeaderValue; - TaggingRequestInterceptor(String deployServiceVersion) { + TaggingRequestFilterFunction(String deployServiceVersion) { this(deployServiceVersion, null, null); } - TaggingRequestInterceptor(String deployServiceVersion, String org, String space) { + TaggingRequestFilterFunction(String deployServiceVersion, String org, String space) { this.headerValue = getHeaderValue(deployServiceVersion); this.orgHeaderValue = org; this.spaceHeaderValue = space; @@ -32,14 +32,14 @@ String getHeaderValue(String deployServiceVersion) { } @Override - public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { - HttpHeaders headers = request.getHeaders(); + public Mono filter(ClientRequest clientRequest, ExchangeFunction nextFilter) { + HttpHeaders headers = clientRequest.headers(); setHeader(headers, TAG_HEADER_NAME, headerValue); if (orgHeaderValue != null && spaceHeaderValue != null) { setHeader(headers, TAG_HEADER_ORG_NAME, orgHeaderValue); setHeader(headers, TAG_HEADER_SPACE_NAME, spaceHeaderValue); } - return execution.execute(request, body); + return nextFilter.exchange(clientRequest); } private void setHeader(HttpHeaders headers, String tagHeaderName, String headerValue) { diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/AbstractServiceGetter.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/AbstractServiceGetter.java index 0c1949e835..0e3e0572d7 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/AbstractServiceGetter.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/AbstractServiceGetter.java @@ -21,8 +21,8 @@ public abstract class AbstractServiceGetter extends CustomControllerClient { private static final String V2_SERVICE_INSTANCES_RESOURCE_PATH = "/v2/service_instances?"; @Inject - public AbstractServiceGetter(RestTemplateFactory restTemplateFactory) { - super(restTemplateFactory); + public AbstractServiceGetter(WebClientFactory webClientFactory) { + super(webClientFactory); } @SuppressWarnings("unchecked") @@ -51,7 +51,11 @@ private Map buildQueryParameters(String serviceName, String spac private Map getCloudServiceInstance(CloudControllerClient client, String serviceInstancesEndpoint, Map queryParameters) { - String response = getRestTemplate(client).getForObject(serviceInstancesEndpoint, String.class, queryParameters); + String response = getWebClient(client).get() + .uri(serviceInstancesEndpoint, queryParameters) + .retrieve() + .bodyToMono(String.class) + .block(); Map serviceInstancesResponse = parseResponse(response); return getCloudServiceInstance(serviceInstancesResponse); } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ApplicationRoutesGetter.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ApplicationRoutesGetter.java index dbba8adddc..133f86ab0d 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ApplicationRoutesGetter.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ApplicationRoutesGetter.java @@ -11,7 +11,7 @@ import org.cloudfoundry.client.lib.CloudControllerClient; import org.cloudfoundry.client.lib.domain.CloudApplication; import org.cloudfoundry.client.lib.domain.CloudRoute; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; @Named public class ApplicationRoutesGetter extends CustomControllerClient { @@ -19,8 +19,8 @@ public class ApplicationRoutesGetter extends CustomControllerClient { private final CloudEntityResourceMapper resourceMapper = new CloudEntityResourceMapper(); @Inject - public ApplicationRoutesGetter(RestTemplateFactory restTemplateFactory) { - super(restTemplateFactory); + public ApplicationRoutesGetter(WebClientFactory webClientFactory) { + super(webClientFactory); } public List getRoutes(CloudControllerClient client, String appName) { @@ -39,10 +39,10 @@ private String getAppRoutesUrl(UUID appGuid) { } private List doGetRoutes(CloudControllerClient client, String appRoutesUrl) { - RestTemplate restTemplate = getRestTemplate(client); + WebClient webClient = getWebClient(client); String cloudControllerUrl = client.getCloudControllerUrl() .toString(); - List> resources = getAllResources(restTemplate, cloudControllerUrl, appRoutesUrl); + List> resources = getAllResources(webClient, cloudControllerUrl, appRoutesUrl); return toCloudRoutes(resources); } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CFOptimizedEventGetter.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CFOptimizedEventGetter.java index 34bd6b42db..578eb46f2a 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CFOptimizedEventGetter.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CFOptimizedEventGetter.java @@ -13,7 +13,7 @@ public class CFOptimizedEventGetter extends CustomControllerClient { private final CloudControllerClient client; public CFOptimizedEventGetter(CloudControllerClient client) { - super(new RestTemplateFactory()); + super(new WebClientFactory()); this.client = client; } @@ -36,8 +36,8 @@ private Map getAsUrlVariablesForFindEventsRequest(String type, S private List executeFindEventsRequest(Map urlVariables) { String controllerUrl = client.getCloudControllerUrl() .toString(); - List> response = getAllResources(getRestTemplate(client), controllerUrl, - FIND_EVENT_BY_TYPE_AND_TIMESTAMP_ENDPOINT, urlVariables); + List> response = getAllResources(getWebClient(client), controllerUrl, FIND_EVENT_BY_TYPE_AND_TIMESTAMP_ENDPOINT, + urlVariables); return extractSpaceIds(response); } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CloudServiceOperator.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CloudServiceOperator.java index 589b73937d..abbdcbe172 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CloudServiceOperator.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CloudServiceOperator.java @@ -19,8 +19,8 @@ public abstract class CloudServiceOperator extends CustomControllerClient { protected static final String SERVICE_PLAN_GUID = "service_plan_guid"; protected static final String SERVICE_TAGS = "tags"; - protected CloudServiceOperator(RestTemplateFactory restTemplateFactory) { - super(restTemplateFactory); + protected CloudServiceOperator(WebClientFactory webClientFactory) { + super(webClientFactory); } protected CloudServicePlan findPlanForService(CloudControllerClient client, CloudServiceInstance serviceInstance, String newPlan) { diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomControllerClient.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomControllerClient.java index ebda363ad4..20d9718ad1 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomControllerClient.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomControllerClient.java @@ -11,38 +11,42 @@ import org.apache.commons.lang3.StringUtils; import org.cloudfoundry.client.lib.CloudControllerClient; import org.cloudfoundry.multiapps.common.util.JsonUtil; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; public abstract class CustomControllerClient { - private final RestTemplateFactory restTemplateFactory; + private final WebClientFactory webClientFactory; - protected CustomControllerClient(RestTemplateFactory restTemplateFactory) { - this.restTemplateFactory = restTemplateFactory; + protected CustomControllerClient(WebClientFactory webClientFactory) { + this.webClientFactory = webClientFactory; } - protected RestTemplate getRestTemplate(CloudControllerClient client) { - return restTemplateFactory.getRestTemplate(client); + protected WebClient getWebClient(CloudControllerClient client) { + return webClientFactory.getWebClient(client); } - protected List> getAllResources(RestTemplate restTemplate, String controllerUrl, String urlPath) { - return getAllResources(restTemplate, controllerUrl, urlPath, Collections.emptyMap()); + protected List> getAllResources(WebClient webClient, String controllerUrl, String urlPath) { + return getAllResources(webClient, controllerUrl, urlPath, Collections.emptyMap()); } - protected List> getAllResources(RestTemplate restTemplate, String controllerUrl, String urlPath, + protected List> getAllResources(WebClient webClient, String controllerUrl, String urlPath, Map urlVariables) { List> allResources = new ArrayList<>(); String nextUrl = urlPath; while (!StringUtils.isEmpty(nextUrl)) { - nextUrl = addPageOfResources(restTemplate, controllerUrl, nextUrl, allResources, urlVariables); + nextUrl = addPageOfResources(webClient, controllerUrl, nextUrl, allResources, urlVariables); } return allResources; } @SuppressWarnings("unchecked") - protected String addPageOfResources(RestTemplate restTemplate, String controllerUrl, String path, - List> allResources, Map urlVariables) { - String response = restTemplate.getForObject(getUrl(controllerUrl, path), String.class, urlVariables); + protected String addPageOfResources(WebClient webClient, String controllerUrl, String path, List> allResources, + Map urlVariables) { + String response = webClient.get() + .uri(getUrl(controllerUrl, path), urlVariables) + .retrieve() + .bodyToMono(String.class) + .block(); Map responseMap = JsonUtil.convertJsonToMap(response); validateResponse(responseMap); List> newResources = (List>) responseMap.get("resources"); diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/EventsGetter.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/EventsGetter.java index 37000a6d34..ca2d501804 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/EventsGetter.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/EventsGetter.java @@ -12,7 +12,7 @@ import org.cloudfoundry.client.lib.CloudControllerClient; import org.cloudfoundry.client.lib.domain.CloudEvent; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; @Named public class EventsGetter extends CustomControllerClient { @@ -26,8 +26,8 @@ public class EventsGetter extends CustomControllerClient { private final CloudEntityResourceMapper resourceMapper = new CloudEntityResourceMapper(); @Inject - public EventsGetter(RestTemplateFactory restTemplateFactory) { - super(restTemplateFactory); + public EventsGetter(WebClientFactory webClientFactory) { + super(webClientFactory); } private Map buildQueryParameters(UUID uuid) { @@ -41,9 +41,9 @@ public List getEvents(UUID uuid, CloudControllerClient client) { String controllerUrl = client.getCloudControllerUrl() .toString(); - RestTemplate restTemplate = getRestTemplate(client); + WebClient webClient = getWebClient(client); - List> resources = getAllResources(restTemplate, controllerUrl, EVENTS_URL, queryParames); + List> resources = getAllResources(webClient, controllerUrl, EVENTS_URL, queryParames); return resources.stream() .filter(Objects::nonNull) diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/RestTemplateFactory.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/RestTemplateFactory.java deleted file mode 100644 index 3be2b6e355..0000000000 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/RestTemplateFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.cloudfoundry.multiapps.controller.core.cf.clients; - -import java.io.IOException; -import java.net.URI; - -import javax.inject.Named; - -import org.cloudfoundry.client.lib.CloudControllerClient; -import org.cloudfoundry.client.lib.util.RestUtil; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.ClientHttpRequest; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.web.client.RestTemplate; - -@Named -public class RestTemplateFactory { - - public RestTemplate getRestTemplate(CloudControllerClient client) { - RestTemplate restTemplate = new RestUtil().createRestTemplate(null, false); - restTemplate.setRequestFactory(new HttpRequestFactory(restTemplate.getRequestFactory(), client)); - return restTemplate; - } - - private static class HttpRequestFactory implements ClientHttpRequestFactory { - - private final ClientHttpRequestFactory requestFactory; - private final CloudControllerClient client; - - public HttpRequestFactory(ClientHttpRequestFactory requestFactory, CloudControllerClient client) { - this.requestFactory = requestFactory; - this.client = client; - } - - @Override - public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { - ClientHttpRequest request = requestFactory.createRequest(uri, httpMethod); - HttpHeaders requestHeaders = request.getHeaders(); - if (!requestHeaders.containsKey(HttpHeaders.AUTHORIZATION)) { - requestHeaders.add(HttpHeaders.AUTHORIZATION, "Bearer " + computeAuthorizationToken()); - } - return request; - } - - private String computeAuthorizationToken() { - return client.login() - .toString(); - } - - } -} diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceInstanceGetter.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceInstanceGetter.java index 87e07ec1f4..3cf32a13d6 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceInstanceGetter.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceInstanceGetter.java @@ -10,8 +10,8 @@ @Named("serviceInstanceGetter") public class ServiceInstanceGetter extends AbstractServiceGetter { - protected ServiceInstanceGetter(RestTemplateFactory restTemplateFactory) { - super(restTemplateFactory); + protected ServiceInstanceGetter(WebClientFactory webClientFactory) { + super(webClientFactory); } @Override diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceUpdater.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceUpdater.java index 5536f93440..1e6bf76f90 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceUpdater.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceUpdater.java @@ -16,12 +16,10 @@ import org.cloudfoundry.multiapps.controller.core.util.MethodExecution.ExecutionState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; @Named public class ServiceUpdater extends CloudServiceOperator { @@ -34,8 +32,8 @@ public class ServiceUpdater extends CloudServiceOperator { private static final String SERVICE_PARAMETERS = "parameters"; @Inject - public ServiceUpdater(RestTemplateFactory restTemplateFactory) { - super(restTemplateFactory); + public ServiceUpdater(WebClientFactory webClientFactory) { + super(webClientFactory); } public MethodExecution updateServicePlanQuietly(CloudControllerClient client, String serviceName, String servicePlan) { @@ -104,16 +102,18 @@ private MethodExecution attemptToUpdateServiceParameters(CloudController private MethodExecution attemptToUpdateServiceParameter(CloudControllerClient client, CloudServiceInstance serviceInstance, String serviceUrl, String parameterName, Object parameter) { - RestTemplate restTemplate = getRestTemplate(client); + WebClient webClient = getWebClient(client); String cloudControllerUrl = getCloudControllerUrl(client); String updateServiceUrl = getUrl(cloudControllerUrl, getUpdateServiceUrl(serviceUrl, serviceInstance.getMetadata() .getGuid() .toString())); - Map serviceRequest = Map.of(parameterName, parameter); - HttpEntity> requestEntity = new HttpEntity<>(serviceRequest); - ResponseEntity response = restTemplate.exchange(updateServiceUrl, HttpMethod.PUT, requestEntity, String.class); - return MethodExecution.fromResponseEntity(response); + ClientResponse clientResponse = webClient.put() + .uri(updateServiceUrl) + .bodyValue(serviceRequest) + .exchange() + .block(); + return MethodExecution.fromClientResponse(clientResponse); } private String getUpdateServiceUrl(String serviceUrl, String serviceGuid) { diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/UserProvidedServiceInstanceGetter.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/UserProvidedServiceInstanceGetter.java index c2f39e0261..f2e78c7a33 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/UserProvidedServiceInstanceGetter.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/UserProvidedServiceInstanceGetter.java @@ -10,8 +10,8 @@ @Named("userProvidedServiceInstanceGetter") public class UserProvidedServiceInstanceGetter extends AbstractServiceGetter { - public UserProvidedServiceInstanceGetter(RestTemplateFactory restTemplateFactory) { - super(restTemplateFactory); + public UserProvidedServiceInstanceGetter(WebClientFactory webClientFactory) { + super(webClientFactory); } @Override diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/WebClientFactory.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/WebClientFactory.java new file mode 100644 index 0000000000..88be60b05e --- /dev/null +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/WebClientFactory.java @@ -0,0 +1,24 @@ +package org.cloudfoundry.multiapps.controller.core.cf.clients; + +import javax.inject.Named; + +import org.cloudfoundry.client.lib.CloudControllerClient; +import org.cloudfoundry.client.lib.util.RestUtil; +import org.springframework.web.reactive.function.client.WebClient; + +@Named +public class WebClientFactory { + + public WebClient getWebClient(CloudControllerClient client) { + WebClient.Builder webClientBuilder = new RestUtil().createWebClient(false) + .mutate(); + webClientBuilder.defaultHeaders(httpHeaders -> httpHeaders.setBearerAuth(computeAuthorizationToken(client))); + return webClientBuilder.build(); + } + + private String computeAuthorizationToken(CloudControllerClient client) { + return client.login() + .toString(); + } + +} diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/MethodExecution.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/MethodExecution.java index d2dd60a17b..56ea7e6c04 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/MethodExecution.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/MethodExecution.java @@ -1,7 +1,7 @@ package org.cloudfoundry.multiapps.controller.core.util; import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; +import org.springframework.web.reactive.function.client.ClientResponse; public class MethodExecution { @@ -21,14 +21,15 @@ public T getResponse() { return response; } - public static MethodExecution fromResponseEntity(ResponseEntity response) { - if (response == null) { + public static MethodExecution fromClientResponse(ClientResponse clientResponse) { + if (clientResponse == null) { return null; } - ExecutionState state = response.getStatusCode() - .equals(HttpStatus.ACCEPTED) ? ExecutionState.EXECUTING : ExecutionState.FINISHED; - String responseEntity = response.getBody(); - return new MethodExecution<>(responseEntity, state); + ExecutionState state = clientResponse.statusCode() + .equals(HttpStatus.ACCEPTED) ? ExecutionState.EXECUTING : ExecutionState.FINISHED; + String response = clientResponse.bodyToMono(String.class) + .block(); + return new MethodExecution<>(response, state); } public enum ExecutionState { diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestFilterFunctionTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestFilterFunctionTest.java new file mode 100644 index 0000000000..6a6c6b861d --- /dev/null +++ b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestFilterFunctionTest.java @@ -0,0 +1,112 @@ +package org.cloudfoundry.multiapps.controller.core.cf; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import java.io.IOException; +import java.net.URI; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.client.reactive.ClientHttpRequest; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import org.springframework.web.reactive.function.client.ExchangeStrategies; + +import reactor.core.publisher.Mono; + +class TaggingRequestFilterFunctionTest { + + private static final String TEST_VERSION_VALUE = "1.58.0"; + private static final String TEST_ORG_VALUE = "faceorg"; + private static final String TEST_SPACE_VALUE = "myspace"; + private HttpHeaders actualHeaders; + private ClientRequest clientRequest; + @Mock + private ExchangeFunction nextFilter; + + @BeforeEach + void setUp() throws Exception { + actualHeaders = new HttpHeaders(); + clientRequest = initializeClientRequest(); + MockitoAnnotations.openMocks(this) + .close(); + } + + private ClientRequest initializeClientRequest() { + return new ClientRequest() { + + @Override + public Map attributes() { + return null; + } + + @Override + public BodyInserter body() { + return null; + } + + @Override + public MultiValueMap cookies() { + return null; + } + + @Override + public HttpHeaders headers() { + return actualHeaders; + } + + @Override + public String logPrefix() { + return null; + } + + @Override + public HttpMethod method() { + return null; + } + + @Override + public URI url() { + return null; + } + + @Override + public Mono writeTo(ClientHttpRequest arg0, ExchangeStrategies arg1) { + return null; + } + }; + } + + @Test + void testInjectOnlyDeployServiceVersion() throws IOException { + TaggingRequestFilterFunction testedFilterFunction = new TaggingRequestFilterFunction(TEST_VERSION_VALUE); + + testedFilterFunction.filter(clientRequest, nextFilter); + + assertEquals("MTA deploy-service v1.58.0", actualHeaders.getFirst(TaggingRequestFilterFunction.TAG_HEADER_NAME)); + assertFalse(actualHeaders.containsKey(TaggingRequestFilterFunction.TAG_HEADER_ORG_NAME)); + assertFalse(actualHeaders.containsKey(TaggingRequestFilterFunction.TAG_HEADER_SPACE_NAME)); + } + + @Test + void testInjectOrgAndSpaceValues() throws IOException { + TaggingRequestFilterFunction testedFilterFunction = new TaggingRequestFilterFunction(TEST_VERSION_VALUE, + TEST_ORG_VALUE, + TEST_SPACE_VALUE); + + testedFilterFunction.filter(clientRequest, nextFilter); + + assertEquals("MTA deploy-service v1.58.0", actualHeaders.getFirst(TaggingRequestFilterFunction.TAG_HEADER_NAME)); + assertEquals(TEST_ORG_VALUE, actualHeaders.getFirst(TaggingRequestFilterFunction.TAG_HEADER_ORG_NAME)); + assertEquals(TEST_SPACE_VALUE, actualHeaders.getFirst(TaggingRequestFilterFunction.TAG_HEADER_SPACE_NAME)); + } + +} diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestInterceptorTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestInterceptorTest.java deleted file mode 100644 index 2ac17f0645..0000000000 --- a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/TaggingRequestInterceptorTest.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.cloudfoundry.multiapps.controller.core.cf; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.URI; -import java.util.Optional; - -import org.cloudfoundry.multiapps.controller.core.util.ApplicationConfiguration; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.AbstractClientHttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpResponse; - -public class TaggingRequestInterceptorTest { - - private static final String TEST_VERSION_VALUE = "1.58.0"; - private static final String TEST_ORG_VALUE = "faceorg"; - private static final String TEST_SPACE_VALUE = "myspace"; - private org.springframework.http.HttpRequest requestStub; - private final byte[] body = new byte[] {}; - @Mock - private ClientHttpRequestExecution execution; - - @Mock - private ApplicationConfiguration configuration; - - @Before - public void setUp() { - requestStub = new AbstractClientHttpRequest() { - - public URI getURI() { - return null; - } - - public HttpMethod getMethod() { - return null; - } - - protected OutputStream getBodyInternal(HttpHeaders headers) { - return null; - } - - protected ClientHttpResponse executeInternal(HttpHeaders headers) { - return null; - } - - @Override - public String getMethodValue() { - return null; - } - - }; - MockitoAnnotations.initMocks(this); - } - - @Test - public void testInjectGenericValue() throws IOException { - TaggingRequestInterceptor testedInterceptor = new TaggingRequestInterceptor("1.58.0"); - testedInterceptor.intercept(requestStub, body, execution); - assertNotNull(requestStub.getHeaders()); - assertTrue(requestStub.getHeaders() - .containsKey(TaggingRequestInterceptor.TAG_HEADER_NAME)); - String expectedValue = "MTA deploy-service v1.58.0"; - Optional foundValue = requestStub.getHeaders() - .get(TaggingRequestInterceptor.TAG_HEADER_NAME) - .stream() - .filter(value -> value.equals(expectedValue)) - .findFirst(); - assertTrue(foundValue.isPresent()); - } - - @Test - public void testInjectOrgAndSpaceValues() throws IOException { - TaggingRequestInterceptor testedInterceptor = new TaggingRequestInterceptor(TEST_VERSION_VALUE, TEST_ORG_VALUE, TEST_SPACE_VALUE); - testedInterceptor.intercept(requestStub, body, execution); - HttpHeaders headers = requestStub.getHeaders(); - assertNotNull(headers); - assertTrue(headers.containsKey(TaggingRequestInterceptor.TAG_HEADER_ORG_NAME)); - assertTrue(headers.containsKey(TaggingRequestInterceptor.TAG_HEADER_SPACE_NAME)); - String expectedValue = "MTA deploy-service v1.58.0"; - Optional foundValue = headers.get(TaggingRequestInterceptor.TAG_HEADER_NAME) - .stream() - .filter(value -> value.equals(expectedValue)) - .findFirst(); - assertTrue(foundValue.isPresent()); - Optional foundOrgValue = headers.get(TaggingRequestInterceptor.TAG_HEADER_ORG_NAME) - .stream() - .filter(value -> value.equals(TEST_ORG_VALUE)) - .findFirst(); - assertTrue(foundOrgValue.isPresent()); - Optional foundSpaceValue = headers.get(TaggingRequestInterceptor.TAG_HEADER_SPACE_NAME) - .stream() - .filter(value -> value.equals(TEST_SPACE_VALUE)) - .findFirst(); - assertTrue(foundSpaceValue.isPresent()); - - } - - @Test - public void testGetHeaderValue() { - TaggingRequestInterceptor testedInterceptor = new TaggingRequestInterceptor(null, null, null); - final String dsversion = "9.9.9-SNAPSHOT"; - String headerValue = testedInterceptor.getHeaderValue(dsversion); - assertTrue(headerValue.contains(dsversion)); - assertTrue(headerValue.contains("deploy-service")); - } - - @Test - public void addHeadersOnlyOnceTest() throws IOException { - TaggingRequestInterceptor testedInterceptor = new TaggingRequestInterceptor(TEST_VERSION_VALUE, TEST_ORG_VALUE, TEST_SPACE_VALUE); - testedInterceptor.intercept(requestStub, body, execution); - testedInterceptor.intercept(requestStub, body, execution); - testedInterceptor.intercept(requestStub, body, execution); - HttpHeaders headers = requestStub.getHeaders(); - String expectedValue = testedInterceptor.getHeaderValue(TEST_VERSION_VALUE); - long tagCount = headers.get(TaggingRequestInterceptor.TAG_HEADER_NAME) - .stream() - .filter(value -> value.equals(expectedValue)) - .count(); - assertEquals("Main tag header occurrence is not 1", 1L, tagCount); - long orgTagCount = headers.get(TaggingRequestInterceptor.TAG_HEADER_ORG_NAME) - .stream() - .filter(value -> value.equals(TEST_ORG_VALUE)) - .count(); - assertEquals("Org tag header occurrence is not 1", 1L, orgTagCount); - long spaceTagCount = headers.get(TaggingRequestInterceptor.TAG_HEADER_SPACE_NAME) - .stream() - .filter(value -> value.equals(TEST_SPACE_VALUE)) - .count(); - assertEquals("Space tag header occurrence is not 1", 1L, spaceTagCount); - } -} diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CloudServiceOperatorTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CloudServiceOperatorTest.java index b71beb035f..60937980d9 100644 --- a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CloudServiceOperatorTest.java +++ b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CloudServiceOperatorTest.java @@ -12,19 +12,33 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; +import org.springframework.web.reactive.function.client.WebClient.RequestBodyUriSpec; +import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec; import com.fasterxml.jackson.core.type.TypeReference; +import reactor.core.publisher.Mono; + public abstract class CloudServiceOperatorTest { private static final String CONTROLLER_URL = "https://api.cf.sap.hana.ondemand.com"; private static final String SERVICE_OFFERINGS_RESPONSE_PATH = "service-offerings.json"; @Mock - private RestTemplate restTemplate; + private WebClient webClient; + @Mock + private RequestBodyUriSpec requestBodyUriSpec; + @Mock + private RequestBodySpec requestBodySpec; @Mock - private RestTemplateFactory restTemplateFactory; + private RequestHeadersSpec requestHeadersSpec; + @Mock + private Mono clientResponse; + @Mock + private WebClientFactory webClientFactory; @Mock private CloudControllerClient client; @@ -33,15 +47,40 @@ protected static String getControllerUrl() { } @BeforeEach - public void prepareClients() throws IOException { - MockitoAnnotations.initMocks(this); - prepareRestTemplateFactory(); + public void prepareClients() throws Exception { + MockitoAnnotations.openMocks(this) + .close(); + prepareWebClient(); + prepareRequesBodyUriSpec(); + prepareRequestBodySpec(); + prepareRequestHeadersSpec(); + prepareWebClientFactory(); prepareClient(); } - private void prepareRestTemplateFactory() { - Mockito.when(restTemplateFactory.getRestTemplate(client)) - .thenReturn(restTemplate); + private void prepareWebClient() { + Mockito.when(webClient.put()) + .thenReturn(requestBodyUriSpec); + } + + private void prepareRequesBodyUriSpec() { + Mockito.when(requestBodyUriSpec.uri(Mockito.anyString())) + .thenReturn(requestBodySpec); + } + + private void prepareRequestBodySpec() { + Mockito.when(requestBodySpec.bodyValue(Mockito.any())) + .thenReturn(requestHeadersSpec); + } + + private void prepareRequestHeadersSpec() { + Mockito.when(requestHeadersSpec.exchange()) + .thenReturn(clientResponse); + } + + private void prepareWebClientFactory() { + Mockito.when(webClientFactory.getWebClient(client)) + .thenReturn(webClient); } private void prepareClient() throws IOException { @@ -60,12 +99,28 @@ private List loadServiceOfferingsFromFile(String filePath) }); } - protected RestTemplate getMockedRestTemplate() { - return restTemplate; + protected WebClient getMockedWebClient() { + return webClient; + } + + protected RequestBodyUriSpec getMockedRequestBodyUriSpec() { + return requestBodyUriSpec; + } + + protected RequestBodySpec getMockedRequestBodySpec() { + return requestBodySpec; + } + + protected Mono getMockedClientResponse() { + return clientResponse; + } + + protected RequestHeadersSpec getMockedRequestHeadersSpec() { + return requestHeadersSpec; } - protected RestTemplateFactory getMockedRestTemplateFactory() { - return restTemplateFactory; + protected WebClientFactory getMockedWebClientFactory() { + return webClientFactory; } protected CloudControllerClient getMockedClient() { diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceUpdaterTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceUpdaterTest.java index 61b5144c84..33b729cd76 100644 --- a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceUpdaterTest.java +++ b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/cf/clients/ServiceUpdaterTest.java @@ -14,7 +14,6 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; -import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; class ServiceUpdaterTest extends CloudServiceOperatorTest { @@ -37,7 +36,7 @@ class ServiceUpdaterTest extends CloudServiceOperatorTest { @BeforeEach void createServiceUpdater() { - serviceUpdater = new ServiceUpdater(getMockedRestTemplateFactory()); + serviceUpdater = new ServiceUpdater(getMockedWebClientFactory()); } @Test @@ -51,12 +50,18 @@ void testUpdateServicePlan1() throws MalformedURLException { validatePlanUpdate("8e886beb-85cb-4455-9474-b6dfda36ffeb"); } - @SuppressWarnings("unchecked") private void validatePlanUpdate(String servicePlanGuid) { String updateServicePlanUrl = getUpdateServicePlanUrl(); - Mockito.verify(getMockedRestTemplate()) - .exchange(ArgumentMatchers.eq(updateServicePlanUrl), ArgumentMatchers.any(HttpMethod.class), ArgumentMatchers.any(), - ArgumentMatchers.any(Class.class)); + Mockito.verify(getMockedWebClient()) + .put(); + Mockito.verify(getMockedRequestBodyUriSpec()) + .uri(ArgumentMatchers.eq(updateServicePlanUrl)); + Mockito.verify(getMockedRequestBodySpec()) + .bodyValue(ArgumentMatchers.any()); + Mockito.verify(getMockedRequestHeadersSpec()) + .exchange(); + Mockito.verify(getMockedClientResponse()) + .block(); } private String getUpdateServicePlanUrl() { diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/client/LoggingCloudControllerClient.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/client/LoggingCloudControllerClient.java index 480419b86d..f498b66b56 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/client/LoggingCloudControllerClient.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/client/LoggingCloudControllerClient.java @@ -10,7 +10,6 @@ import org.cloudfoundry.client.lib.ApplicationServicesUpdateCallback; import org.cloudfoundry.client.lib.CloudControllerClient; -import org.cloudfoundry.client.lib.RestLogCallback; import org.cloudfoundry.client.lib.StartingInfo; import org.cloudfoundry.client.lib.UploadStatusCallback; import org.cloudfoundry.client.lib.domain.ApplicationLog; @@ -40,7 +39,6 @@ import org.cloudfoundry.multiapps.controller.core.util.UserMessageLogger; import org.cloudfoundry.multiapps.controller.process.Messages; import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.web.client.ResponseErrorHandler; public class LoggingCloudControllerClient implements CloudControllerClient { @@ -759,21 +757,6 @@ public void logout() { delegate.logout(); } - @Override - public void registerRestLogListener(RestLogCallback callBack) { - delegate.registerRestLogListener(callBack); - } - - @Override - public void setResponseErrorHandler(ResponseErrorHandler errorHandler) { - delegate.setResponseErrorHandler(errorHandler); - } - - @Override - public void unRegisterRestLogListener(RestLogCallback callBack) { - delegate.unRegisterRestLogListener(callBack); - } - @Override public DropletInfo getCurrentDropletForApplication(UUID applicationGuid) { logger.debug(Messages.GETTING_THE_CURRENT_DROPLET_FOR_APPLICATION_0, applicationGuid); diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/configuration/UAAClientConfiguration.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/configuration/UAAClientConfiguration.java index 1942fe0fde..cb6d312d8d 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/configuration/UAAClientConfiguration.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/configuration/UAAClientConfiguration.java @@ -13,8 +13,7 @@ import org.cloudfoundry.multiapps.controller.core.util.SSLUtil; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; @Configuration public class UAAClientConfiguration { @@ -48,12 +47,16 @@ private URL readTokenEndpoint(URL targetURL) { } protected Map getControllerInfo(URL targetURL) { - String infoURL = targetURL.toString() + CONTROLLER_INFO_ENDPOINT; - ResponseEntity infoResponse = new RestTemplate().getForEntity(infoURL, String.class); - if (infoResponse.getBody() == null) { + String infoResponse = WebClient.create(targetURL.toString()) + .get() + .uri(CONTROLLER_INFO_ENDPOINT) + .retrieve() + .bodyToMono(String.class) + .block(); + if (infoResponse == null) { throw new IllegalStateException(MessageFormat.format("Invalid response returned from {0}", CONTROLLER_INFO_ENDPOINT)); } - return JsonUtil.convertJsonToMap(infoResponse.getBody()); + return JsonUtil.convertJsonToMap(infoResponse); } } diff --git a/pom.xml b/pom.xml index c7d86c96d6..1cae0270be 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 org.cloudfoundry.multiapps @@ -42,7 +43,7 @@ 2.11.2 4.0.0 3.0.0 - 1.29.0 + 1.30.0-SNAPSHOT 4.0.1.201506240215-r 1.6.2 2.2.1 @@ -148,8 +149,8 @@ maven-surefire-plugin 2.22.2 - + @@ -377,8 +378,8 @@ jaxb-impl ${jaxb-impl.version} - + org.yaml @@ -591,6 +592,12 @@ spring-web ${spring.version} + + + org.springframework + spring-webflux + ${spring.version} + org.springframework @@ -700,8 +707,8 @@ ${liquibase.version} - + javax.xml.bind jaxb-api