
com.sap.cloudfoundry.client.facade.adapters.CloudFoundryClientFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cloudfoundry-client-facade Show documentation
Show all versions of cloudfoundry-client-facade Show documentation
A facade of the official Cloud Foundry Java client
package com.sap.cloudfoundry.client.facade.adapters;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.text.MessageFormat;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v3.organizations.OrganizationsV3;
import org.cloudfoundry.client.v3.spaces.SpacesV3;
import org.cloudfoundry.reactor.ConnectionContext;
import org.cloudfoundry.reactor.DefaultConnectionContext;
import org.cloudfoundry.reactor.client.ReactorCloudFoundryClient;
import org.cloudfoundry.reactor.client.v3.organizations.ReactorOrganizationsV3;
import org.cloudfoundry.reactor.client.v3.spaces.ReactorSpacesV3;
import org.immutables.value.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import com.sap.cloudfoundry.client.facade.CloudException;
import com.sap.cloudfoundry.client.facade.CloudOperationException;
import com.sap.cloudfoundry.client.facade.Messages;
import com.sap.cloudfoundry.client.facade.oauth2.OAuthClient;
import com.sap.cloudfoundry.client.facade.rest.CloudSpaceClient;
import com.sap.cloudfoundry.client.facade.util.CloudUtil;
import com.sap.cloudfoundry.client.facade.util.JsonUtil;
import reactor.core.publisher.Mono;
@Value.Immutable
public abstract class CloudFoundryClientFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(CloudFoundryClientFactory.class);
static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
.executor(Executors.newSingleThreadExecutor())
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofMinutes(10))
.build();
private final Map connectionContextCache = new ConcurrentHashMap<>();
public abstract Optional getSslHandshakeTimeout();
public abstract Optional getConnectTimeout();
public abstract Optional getConnectionPoolSize();
public abstract Optional getThreadPoolSize();
public abstract Optional getResponseTimeout();
public CloudFoundryClient createClient(URL controllerUrl, OAuthClient oAuthClient, Map requestTags) {
return ReactorCloudFoundryClient.builder()
.connectionContext(getOrCreateConnectionContext(controllerUrl.getHost()))
.tokenProvider(oAuthClient.getTokenProvider())
.requestTags(requestTags)
.build();
}
public LogCacheClient createLogCacheClient(URL controllerUrl, OAuthClient oAuthClient, Map requestTags) {
return new LogCacheClient(oAuthClient, requestTags, getOrCreateConnectionContext(controllerUrl.getHost()));
}
@SuppressWarnings("unchecked")
private Map callCfRoot(URL controllerUrl, Map requestTags) {
HttpResponse response;
try {
HttpRequest request = buildCfRootRequest(controllerUrl, requestTags);
LOGGER.info(MessageFormat.format(Messages.CALLING_CF_ROOT_0_TO_ACCESS_LOG_CACHE_URL, controllerUrl));
response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() / 100 != 2) {
var status = HttpStatus.valueOf(response.statusCode());
throw new CloudOperationException(status, status.getReasonPhrase(), response.body());
}
LOGGER.info(Messages.CF_ROOT_REQUEST_FINISHED);
} catch (InterruptedException | URISyntaxException | IOException e) {
throw new CloudException(e.getMessage(), e);
}
var map = JsonUtil.convertJsonToMap(response.body());
return (Map) map.get("links");
}
private HttpRequest buildCfRootRequest(URL controllerUrl, Map requestTags) throws URISyntaxException {
var requestBuilder = HttpRequest.newBuilder()
.GET()
.uri(controllerUrl.toURI())
.timeout(Duration.ofMinutes(5));
requestTags.forEach(requestBuilder::header);
return requestBuilder.build();
}
public CloudSpaceClient createSpaceClient(URL controllerUrl, OAuthClient oAuthClient, Map requestTags) {
String v3Api;
try {
var links = CloudUtil.executeWithRetry(() -> callCfRoot(controllerUrl, requestTags));
@SuppressWarnings("unchecked")
var ccv3 = (Map) links.get("cloud_controller_v3");
v3Api = (String) ccv3.get("href");
} catch (CloudException e) {
LOGGER.warn(MessageFormat.format(Messages.CALL_TO_0_FAILED_WITH_1, controllerUrl.toString(), e.getMessage()), e);
v3Api = controllerUrl + "/v3";
}
var spacesV3 = createV3SpacesClient(controllerUrl, v3Api, oAuthClient, requestTags);
var orgsV3 = createV3OrgsClient(controllerUrl, v3Api, oAuthClient, requestTags);
return new CloudSpaceClient(spacesV3, orgsV3);
}
private SpacesV3 createV3SpacesClient(URL controllerUrl, String v3Api, OAuthClient oAuthClient, Map requestTags) {
return new ReactorSpacesV3(getOrCreateConnectionContext(controllerUrl.getHost()),
Mono.just(v3Api),
oAuthClient.getTokenProvider(),
requestTags);
}
private OrganizationsV3 createV3OrgsClient(URL controllerUrl, String v3Api, OAuthClient oAuthClient, Map requestTags) {
return new ReactorOrganizationsV3(getOrCreateConnectionContext(controllerUrl.getHost()),
Mono.just(v3Api),
oAuthClient.getTokenProvider(),
requestTags);
}
public ConnectionContext getOrCreateConnectionContext(String controllerApiHost) {
return connectionContextCache.computeIfAbsent(controllerApiHost, this::createConnectionContext);
}
private ConnectionContext createConnectionContext(String controllerApiHost) {
DefaultConnectionContext.Builder builder = DefaultConnectionContext.builder()
.apiHost(controllerApiHost);
getSslHandshakeTimeout().ifPresent(builder::sslHandshakeTimeout);
getConnectTimeout().ifPresent(builder::connectTimeout);
getConnectionPoolSize().ifPresent(builder::connectionPoolSize);
getThreadPoolSize().ifPresent(builder::threadPoolSize);
builder.additionalHttpClientConfiguration(this::getAdditionalHttpClientConfiguration);
return builder.build();
}
private reactor.netty.http.client.HttpClient getAdditionalHttpClientConfiguration(reactor.netty.http.client.HttpClient client) {
var clientWithOptions = client;
if (getResponseTimeout().isPresent()) {
clientWithOptions = clientWithOptions.responseTimeout(getResponseTimeout().get());
}
return clientWithOptions;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy