diff --git a/multiapps-controller-client/pom.xml b/multiapps-controller-client/pom.xml
index acfb0201c9..ee32a60a98 100644
--- a/multiapps-controller-client/pom.xml
+++ b/multiapps-controller-client/pom.xml
@@ -85,17 +85,19 @@
value
provided
-
-
- org.cloudfoundry
- cloudfoundry-client-reactor
-
-
+
io.projectreactor.netty
reactor-netty
+
+
+
+ commons-logging
+ commons-logging
+ ${commons-logging.version}
+
@@ -140,30 +142,6 @@
-
- org.cloudfoundry
- cloudfoundry-client-reactor
- ${cloudfoundry-client.version}
-
-
-
- org.slf4j
- jcl-over-slf4j
-
-
-
- com.fasterxml.jackson.core
- jackson-databind
-
-
-
commons-logging
diff --git a/multiapps-controller-client/src/main/java/module-info.java b/multiapps-controller-client/src/main/java/module-info.java
index 4201bc0a0b..dfd1045713 100644
--- a/multiapps-controller-client/src/main/java/module-info.java
+++ b/multiapps-controller-client/src/main/java/module-info.java
@@ -12,7 +12,6 @@
exports org.cloudfoundry.multiapps.controller.client.facade.util;
exports org.cloudfoundry.multiapps.controller.client.facade.dto;
- requires transitive org.cloudfoundry.client;
requires spring.security.oauth2.core;
requires transitive spring.web;
@@ -20,9 +19,7 @@
requires org.apache.commons.collections4;
requires org.apache.commons.io;
requires org.apache.commons.logging;
- requires org.cloudfoundry.client.reactor;
requires org.cloudfoundry.multiapps.common;
- requires org.cloudfoundry.util;
requires org.slf4j;
requires java.net.http;
requires spring.core;
@@ -41,5 +38,7 @@
requires static java.compiler;
requires static jakarta.inject;
requires static org.immutables.value;
+ requires io.netty.codec;
+ requires java.desktop;
}
\ No newline at end of file
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/Constants.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/Constants.java
new file mode 100644
index 0000000000..705fc88798
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/Constants.java
@@ -0,0 +1,38 @@
+package org.cloudfoundry.multiapps.controller;
+
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+
+public class Constants {
+
+ public static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofMinutes(1);
+ public static final Duration JOB_POLL_MIN_INTERVAL = Duration.ofSeconds(1);
+ public static final Duration JOB_POLL_MAX_INTERVAL = Duration.ofSeconds(15);
+ public static final Duration DELETE_JOB_TIMEOUT = Duration.ofMinutes(5);
+ public static final Duration BINDING_OPERATIONS_TIMEOUT = Duration.ofMinutes(10);
+ public static final long PACKAGE_UPLOAD_JOB_POLLING_PERIOD = TimeUnit.SECONDS.toMillis(5);
+
+ public static final int DEFAULT_CONNECTION_POOL_SIZE = 192;
+ public static final int UNDEFINED_PORT = -1;
+ public static final int MAX_CONCURRENT_PAGES = 256;
+ public static final int DEFAULT_CONCURRENT_TASKS = 256;
+ public static final int MAX_CHAR_LENGTH_FOR_PARAMS_IN_REQUEST = 4000;
+
+ public static final String CONNECTION_POOL_NAME = "cf-controller-client";
+ public static final String LOOP_RESOURCES_SUFFIX = "-loop-resources";
+ public static final String CF_API_V3 = "/v3";
+ public static final String HREF = "href";
+ public static final String CLOUD_CONTROLLER_CF_ROOT_DOCUMENT_NAME = "cloud_controller_v3";
+ public static final String LOG_CACHE_CF_ROOT_DOCUMENT_NAME = "log_cache";
+ public static final String API_HOST_PREFIX = "api.";
+ public static final String LOG_CACHE_PREFIX = "log-cache.";
+ public static final String ROOT_DOCUMENT_LINKS_LIST = "links";
+
+ public static final String EMPTY_STRING = "";
+ public static final String COLON = ":";
+ public static final String PROTOCOL_SEPARATOR = "://";
+
+ public static final String PACKAGE_LINK = "package";
+ public static final String WEB_PROCESS_TYPE = "web";
+
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/Messages.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/Messages.java
index af0d03d5f0..8705623590 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/Messages.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/Messages.java
@@ -3,9 +3,52 @@
public class Messages {
// INFO messages
- public static final String WAITING_MS_BEFORE_RETRYING_WITH_TIMEOUT_OF_MS = "Waiting: {} ms before retrying with timeout of: {} ms";
+ public static final String WAITING_MS_BEFORE_RETRYING_WITH_TIMEOUT_OF_MS = "Waiting: {} ms before retrying with timeout of: {} ms.";
public static final String RATE_LIMITED_BY_CC_WAITING_S = "CC returned 429 with Retry-After: {} s. Waiting {} s (capped) before retrying.";
public static final String RATE_LIMITED_BY_CC_NO_HEADER_WAITING_MS = "CC returned 429 without Retry-After header. Waiting {} ms before retrying.";
public static final String RANDOM_WAIT_BEFORE_RETRY_MS = "Waiting {} ms (randomized) before retrying failed CC operation.";
+ // Exception messages
+ public static final String ERROR_OCCURRED_SETTING_UP_DEFAULT_SSL_CONTEXT = "An error occurred while setting up the default SSLContext.";
+ public static final String ERROR_OCCURRED_SETTING_UP_ALWAYS_APPROVING_SSL_CONTEXT = "An error occurred while setting up the always approving SSLContext.";
+ public static final String COULD_NOT_DETERMINE_API_ORIGIN_FROM_0 = "Could not determine the API origin from \"{0}\".";
+ public static final String COULD_NOT_RESOLVE_URL_FROM_0_1 = "Could not resolve URL from \"{0}\" \"{1}\".";
+ public static final String COULD_NOT_RESOLVE_LOG_CACHE_URL_FROM_0 = "Could not derive the log-cache URL from \"{0}\".";
+ public static final String CF_ROOT_DOCUMENT_REQUEST_TO_0_RETURNED_1 = "CF root request to \"{0}\" returned \"{1}\".";
+ public static final String INTERRUPTED_WHILE_CALLING_THE_CF_ROOT_URL_AT_0 = "Interrupted while calling the CF root URL at \"{0}\".";
+ public static final String FAILED_TO_CALL_THE_CF_ROOT_AT_0_WITH_1 = "Failed to call the CF root at \"{0}\" with: \"{1}\".";
+ public static final String SERVICE_KEY_0_NOT_FOUND = "Service key \"{0}\" not found.";
+ public static final String SERVICE_INSTANCE_0_NOT_FOUND = "Service instance \"{0}\" not found.";
+ public static final String SERVICE_BROKER_0_NOT_FOUND = "Service broker \"{0}\" not found.";
+ public static final String APPLICATION_0_NOT_FOUND = "Application \"{0}\" not found.";
+ public static final String DOMAIN_0_NOT_FOUND = "Domain \"{0}\" not found.";
+ public static final String SERVICE_PLAN_0_NOT_FOUND = "Service plan \"{0}\" not found.";
+ public static final String STACK_0_NOT_FOUND = "Stack \"{0}\" not found.";
+ public static final String ORGANISATION_0_NOT_FOUND = "Organization \"{0}\" not found.";
+ public static final String SPACE_WITH_GUID_0_NOT_FOUND = "Space with GUID \"{0}\" not found.";
+ public static final String APPLICATION_WITH_GUID_0_DOES_NOT_HAVE_A_DROPLET = "Application with guid \"{0}\" does not have a droplet";
+ public static final String HOST_0_NOT_FOUND_FOR_DOMAIN_1 = "Host \"{0}\" not found for domain \"{1}\".";
+ public static final String UNABLE_TO_0_WITHOUT_SPECIFYING_ORGANIZATION_AND_SPACE_TO_USE = "Unable to \"{0}\" without specifying organization and space to use.";
+ public static final String DOMAIN_0_NOT_FOUND_FOR_URI_1 = "Domain \"{0}\" not found for URI \"{1}\"";
+ public static final String SERVICE_BINDING_BETWEEN_SERVICE_WITH_GUID_0_AND_APPLICATION_WITH_GUID_1_NOT_FOUND = "Service binding between service with GUID \"{0}\" and application with GUID \"{1}\" not found.";
+ public static final String SERVICE_PLAN_WITH_GUID_0_NOT_AVAILABLE_FOR_SERVICE_INSTANCE_1 = "Service plan with guid \"{0}\" is not available for service instance \"{1}\".";
+ public static final String NO_SERVICE_PLAN_FOUND = "Service plan with guid \"{0}\" for service instance with name \"{1}\" was not found.";
+ public static final String SERVICE_OFFERING_WITH_GUID_0_IS_NOT_AVAILABLE = "Service offering with guid \"{0}\" is not available.";
+ public static final String SERVICE_OFFERING_WITH_GUID_0_NOT_FOUND = "Service offering with guid \"{0}\" not found.";
+ public static final String TARGET_SPACE_REQUIRED_TO_CREATE_AN_APPLICATION = "A target space is required to create an application.";
+ public static final String JOB_0_DID_NOT_COMPLETE_WITHIN_1 = "Job \"{0}\" did not complete within \"{1}\"";
+ public static final String ORGANIZATION_WITH_GUID_0_NOT_FOUND = "Organization with GUID \"{0}\" not found.";
+ public static final String SPACE_0_NOT_FOUND_IN_ORGANIZATION_1 = "Space \"{0}\" not found in organization \"{1}\"";
+ public static final String INTERRUPTED_WHILE_POLLING_ASYNC_JOB_0 = "Interrupted while polling an async job: \"{0}\"";
+ public static final String UNKNOWN_JOB_STATE_0 = "Unknown job state: \"{0}\"";
+ public static final String UNKNOWN_SERVICE_INSTANCE_TYPE_0 = "Unknown service instance type: \"{0}\"";
+ public static final String UNKNOWN_USER_ROLE_0 = "Unknown user role: \"{0}\"";
+
+ //Status texts
+ public static final String NOT_FOUND = "Not Found";
+ public static final String JOB_TIMEOUT = "Job Timeout";
+ public static final String JOB_FAILED = "Job Failed";
+ public static final String BAD_REQUEST = "Bad Request";
+ public static final String FORBIDDEN = "Forbidden";
+
}
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 acffeeb34c..94da22f577 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
@@ -10,7 +10,6 @@
import java.util.function.Function;
import java.util.function.Supplier;
-import org.cloudfoundry.client.v3.Metadata;
import org.cloudfoundry.multiapps.controller.client.facade.ApplicationServicesUpdateCallback;
import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClient;
import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClientImpl;
@@ -35,6 +34,7 @@
import org.cloudfoundry.multiapps.controller.client.facade.domain.DockerInfo;
import org.cloudfoundry.multiapps.controller.client.facade.domain.DropletInfo;
import org.cloudfoundry.multiapps.controller.client.facade.domain.InstancesInfo;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.Metadata;
import org.cloudfoundry.multiapps.controller.client.facade.domain.ServicePlanVisibility;
import org.cloudfoundry.multiapps.controller.client.facade.domain.Staging;
import org.cloudfoundry.multiapps.controller.client.facade.domain.Upload;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/AllowNulls.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/AllowNulls.java
new file mode 100644
index 0000000000..944e54edf6
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/AllowNulls.java
@@ -0,0 +1,11 @@
+package org.cloudfoundry.multiapps.controller.client.facade;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface AllowNulls {
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/CloudControllerClient.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/CloudControllerClient.java
index 2d8f04ccdf..89f8dec346 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/CloudControllerClient.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/CloudControllerClient.java
@@ -8,7 +8,7 @@
import java.util.Set;
import java.util.UUID;
-import org.cloudfoundry.client.v3.Metadata;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.Metadata;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudApplication;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudAsyncJob;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudBuild;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/CloudControllerClientImpl.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/CloudControllerClientImpl.java
index ca0386040c..e016da176c 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/CloudControllerClientImpl.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/CloudControllerClientImpl.java
@@ -11,8 +11,6 @@
import java.util.UUID;
import java.util.function.Supplier;
-import org.cloudfoundry.AbstractCloudFoundryException;
-import org.cloudfoundry.client.v3.Metadata;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudApplication;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudAsyncJob;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudBuild;
@@ -32,6 +30,7 @@
import org.cloudfoundry.multiapps.controller.client.facade.domain.DockerInfo;
import org.cloudfoundry.multiapps.controller.client.facade.domain.DropletInfo;
import org.cloudfoundry.multiapps.controller.client.facade.domain.InstancesInfo;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.Metadata;
import org.cloudfoundry.multiapps.controller.client.facade.domain.ServicePlanVisibility;
import org.cloudfoundry.multiapps.controller.client.facade.domain.Staging;
import org.cloudfoundry.multiapps.controller.client.facade.domain.Upload;
@@ -40,7 +39,6 @@
import org.cloudfoundry.multiapps.controller.client.facade.rest.CloudControllerRestClient;
import org.cloudfoundry.multiapps.controller.client.facade.rest.CloudControllerRestClientFactory;
import org.cloudfoundry.multiapps.controller.client.facade.rest.ImmutableCloudControllerRestClientFactory;
-import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
/**
@@ -659,16 +657,9 @@ private void handleExceptions(Runnable runnable) {
}
private T handleExceptions(Supplier runnable) {
- try {
- return runnable.get();
- } catch (AbstractCloudFoundryException e) {
- throw convertV3ClientException(e);
- }
- }
-
- private CloudOperationException convertV3ClientException(AbstractCloudFoundryException e) {
- HttpStatus httpStatus = HttpStatus.valueOf(e.getStatusCode());
- return new CloudOperationException(httpStatus, httpStatus.getReasonPhrase(), e.getMessage(), e);
+ // The underlying CloudControllerRestClient already surfaces failures as CloudOperationException
+ // (via CloudControllerResponseErrorHandler), so no exception translation is needed here.
+ return runnable.get();
}
}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/CloudFoundryClientFactory.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/CloudFoundryClientFactory.java
deleted file mode 100644
index 5461f765a8..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/CloudFoundryClientFactory.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package org.cloudfoundry.multiapps.controller.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 org.cloudfoundry.multiapps.controller.client.facade.CloudException;
-import org.cloudfoundry.multiapps.controller.client.facade.CloudOperationException;
-import org.cloudfoundry.multiapps.controller.client.facade.Messages;
-import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuthClient;
-import org.cloudfoundry.multiapps.controller.client.facade.rest.CloudSpaceClient;
-import org.cloudfoundry.multiapps.controller.client.facade.util.CloudUtil;
-import org.cloudfoundry.multiapps.controller.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;
- }
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/LogCacheClient.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/LogCacheClient.java
index ea8d519b3f..304a80dff8 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/LogCacheClient.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/LogCacheClient.java
@@ -1,19 +1,5 @@
package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-import org.cloudfoundry.multiapps.controller.client.facade.CloudException;
-import org.cloudfoundry.multiapps.controller.client.facade.Messages;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ApplicationLog;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableApplicationLog;
-import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuthClient;
-import org.cloudfoundry.logcache.v1.Envelope;
-import org.cloudfoundry.logcache.v1.EnvelopeType;
-import org.cloudfoundry.logcache.v1.ReadRequest;
-import org.cloudfoundry.logcache.v1.ReadResponse;
-import org.cloudfoundry.reactor.ConnectionContext;
-import org.cloudfoundry.reactor.logcache.v1.ReactorLogCacheClient;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.time.Duration;
@@ -24,77 +10,72 @@
import java.util.Base64;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
+import org.cloudfoundry.multiapps.controller.client.facade.CloudException;
+import org.cloudfoundry.multiapps.controller.client.facade.Messages;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.ApplicationLog;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableApplicationLog;
+import org.cloudfoundry.multiapps.controller.client.facade.rest.resources.LogCacheReadResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.client.RestClient;
+
public class LogCacheClient {
private static final Logger LOGGER = LoggerFactory.getLogger(LogCacheClient.class);
private static final String SOURCE_TYPE_KEY_NAME = "source_type";
private static final int MAX_LOG_COUNT = 1000;
- private final OAuthClient oAuthClient;
- private final Map requestTags;
- private final ConnectionContext connectionContext;
- public LogCacheClient(OAuthClient oAuthClient, Map requestTags, ConnectionContext connectionContext) {
- this.oAuthClient = oAuthClient;
- this.requestTags = requestTags;
- this.connectionContext = connectionContext;
+ private final RestClient restClient;
+
+ public LogCacheClient(RestClient restClient) {
+ this.restClient = restClient;
}
public List getRecentLogs(UUID applicationGuid, LocalDateTime offset) {
LOGGER.info(Messages.TRYING_TO_GET_APP_LOGS);
- org.cloudfoundry.logcache.v1.LogCacheClient logCacheClient = createReactorLogCacheClient();
- ReadResponse applicationLogsResponse = readApplicationLogs(logCacheClient, applicationGuid, offset);
+ LogCacheReadResponse response = readApplicationLogs(applicationGuid, offset);
- if (applicationLogsResponse != null) {
- LOGGER.info(Messages.APP_LOGS_WERE_FETCHED_SUCCESSFULLY);
- return applicationLogsResponse.getEnvelopes()
- .getBatch()
- .stream()
- .map(this::mapToAppLog)
- // we use a linked list so that the log messages can be a LIFO sequence
- // that way, we avoid unnecessary sorting and copying to and from another collection/array
- .collect(LinkedList::new, LinkedList::addFirst, LinkedList::addAll);
- } else {
+ if (response == null) {
throw new CloudException(MessageFormat.format(Messages.FAILED_TO_FETCH_APP_LOGS_FOR_APP, applicationGuid));
}
+ LOGGER.info(Messages.APP_LOGS_WERE_FETCHED_SUCCESSFULLY);
+ return response.batch()
+ .stream()
+ .map(this::mapToAppLog)
+ // we use a linked list so that the log messages can be a LIFO sequence
+ // that way, we avoid unnecessary sorting and copying to and from another collection/array
+ .collect(LinkedList::new, LinkedList::addFirst, LinkedList::addAll);
}
- private ReactorLogCacheClient createReactorLogCacheClient() {
- return ReactorLogCacheClient.builder()
- .requestTags(requestTags)
- .connectionContext(connectionContext)
- .tokenProvider(oAuthClient.getTokenProvider())
- .build();
- }
-
- private ReadResponse readApplicationLogs(org.cloudfoundry.logcache.v1.LogCacheClient logCacheClient, UUID applicationGuid,
- LocalDateTime offset) {
+ private LogCacheReadResponse readApplicationLogs(UUID applicationGuid, LocalDateTime offset) {
var instant = offset.toInstant(ZoneOffset.UTC);
var secondsInNanos = Duration.ofSeconds(instant.getEpochSecond())
.toNanos();
- return logCacheClient.read(ReadRequest.builder()
- .envelopeType(EnvelopeType.LOG)
- .sourceId(applicationGuid.toString())
- .descending(Boolean.TRUE)
- .limit(MAX_LOG_COUNT)
- .startTime(secondsInNanos + instant.getNano() + 1)
- .build())
- .block();
+ long startTime = secondsInNanos + instant.getNano() + 1;
+
+ return restClient.get()
+ .uri(uriBuilder -> uriBuilder.path("/api/v1/read/{sourceId}")
+ .queryParam("envelope_types", "LOG")
+ .queryParam("descending", Boolean.TRUE)
+ .queryParam("limit", MAX_LOG_COUNT)
+ .queryParam("start_time", startTime)
+ .build(applicationGuid.toString()))
+ .retrieve()
+ .body(LogCacheReadResponse.class);
}
- private ApplicationLog mapToAppLog(Envelope envelope) {
+ private ApplicationLog mapToAppLog(LogCacheReadResponse.Envelope envelope) {
return ImmutableApplicationLog.builder()
- .applicationGuid(envelope.getSourceId())
- .message(decodeLogPayload(envelope.getLog()
- .getPayload()))
- .timestamp(fromLogTimestamp(envelope.getTimestamp()))
- .messageType(fromLogMessageType(envelope.getLog()
- .getType()
- .getValue()))
- .sourceName(envelope.getTags()
+ .applicationGuid(envelope.sourceId())
+ .message(decodeLogPayload(envelope.log()
+ .payload()))
+ .timestamp(fromLogTimestamp(envelope.timestamp()))
+ .messageType(fromLogMessageType(envelope.log()
+ .type()))
+ .sourceName(envelope.tags()
.get(SOURCE_TYPE_KEY_NAME))
.build();
}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/OAuthTokenProvider.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/OAuthTokenProvider.java
deleted file mode 100644
index ff5def4c97..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/OAuthTokenProvider.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.reactor.ConnectionContext;
-import org.cloudfoundry.reactor.TokenProvider;
-
-import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuthClient;
-
-import reactor.core.publisher.Mono;
-
-public class OAuthTokenProvider implements TokenProvider {
-
- private final OAuthClient oAuthClient;
-
- public OAuthTokenProvider(OAuthClient oAuthClient) {
- this.oAuthClient = oAuthClient;
- }
-
- @Override
- public Mono getToken(ConnectionContext connectionContext) {
- return Mono.fromSupplier(() -> {
- OAuth2AccessTokenWithAdditionalInfo token = oAuthClient.getToken();
- return token.getAuthorizationHeaderValue();
- });
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudApplication.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudApplication.java
deleted file mode 100644
index 898cea1a8a..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudApplication.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudApplication;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudSpace;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Derivable;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudApplication;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableLifecycle;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Lifecycle;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.LifecycleType;
-import org.cloudfoundry.client.v3.BuildpackData;
-import org.cloudfoundry.client.v3.CnbData;
-import org.cloudfoundry.client.v3.LifecycleData;
-import org.cloudfoundry.client.v3.applications.Application;
-import org.cloudfoundry.client.v3.applications.ApplicationState;
-import org.immutables.value.Value;
-
-@Value.Immutable
-public abstract class RawCloudApplication extends RawCloudEntity {
-
- public static final String BUILDPACKS = "buildpacks";
- public static final String STACK = "stack";
-
- public abstract Application getApplication();
-
- public abstract Derivable getSpace();
-
- @Override
- public CloudApplication derive() {
- Application app = getApplication();
- return ImmutableCloudApplication.builder()
- .metadata(parseResourceMetadata(app))
- .v3Metadata(app.getMetadata())
- .name(app.getName())
- .state(parseState(app.getState()))
- .lifecycle(parseLifecycle(app.getLifecycle()))
- .space(getSpace().derive())
- .build();
- }
-
- private static CloudApplication.State parseState(ApplicationState state) {
- return CloudApplication.State.valueOf(state.getValue());
- }
-
- private static Lifecycle parseLifecycle(org.cloudfoundry.client.v3.Lifecycle lifecycle) {
- Map data = extractLifecycleData(lifecycle.getData());
-
- return ImmutableLifecycle.builder()
- .type(LifecycleType.valueOf(lifecycle.getType()
- .toString()
- .toUpperCase()))
- .data(data)
- .build();
- }
-
- private static Map extractLifecycleData(LifecycleData lifecycleData) {
- if (lifecycleData instanceof BuildpackData buildpackData) {
- return Map.of(
- BUILDPACKS, buildpackData.getBuildpacks(),
- STACK, buildpackData.getStack());
- } else if (lifecycleData instanceof CnbData cnbData) {
- return Map.of(
- BUILDPACKS, cnbData.getBuildpacks(),
- STACK, cnbData.getStack());
- } else {
- return Collections.emptyMap();
- }
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudAsyncJob.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudAsyncJob.java
deleted file mode 100644
index 1e8bad359c..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudAsyncJob.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.stream.Collectors;
-
-import org.cloudfoundry.client.v3.jobs.Job;
-import org.cloudfoundry.client.v3.jobs.Warning;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudAsyncJob;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudAsyncJob;
-
-@Value.Immutable
-public abstract class RawCloudAsyncJob extends RawCloudEntity {
-
- @Value.Parameter
- public abstract Job getJob();
-
- @Override
- public CloudAsyncJob derive() {
- Job job = getJob();
- return ImmutableCloudAsyncJob.builder()
- .metadata(parseResourceMetadata(job))
- .state(job.getState())
- .operation(job.getOperation())
- .warnings(getWarnings(job))
- .errors(getErrors(job))
- .build();
- }
-
- private String getWarnings(Job job) {
- return job.getWarnings()
- .stream()
- .map(Warning::getDetail)
- .collect(Collectors.joining(","));
- }
-
- private String getErrors(Job job) {
- return job.getErrors()
- .stream()
- .map(this::joinErrorDetails)
- .collect(Collectors.joining(","));
- }
-
- private String joinErrorDetails(org.cloudfoundry.client.v3.Error error) {
- return String.join(" ", error.getCode()
- .toString(),
- error.getTitle(), error.getDetail());
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudBuild.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudBuild.java
deleted file mode 100644
index 2cdbc39eaa..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudBuild.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.Optional;
-
-import org.cloudfoundry.client.v3.Relationship;
-import org.cloudfoundry.client.v3.builds.Build;
-import org.cloudfoundry.client.v3.builds.BuildState;
-import org.cloudfoundry.client.v3.builds.CreatedBy;
-import org.cloudfoundry.client.v3.builds.Droplet;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudBuild;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.DropletInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudBuild;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudBuild.ImmutableCreatedBy;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudBuild.ImmutablePackageInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableDropletInfo;
-
-@Value.Immutable
-public abstract class RawCloudBuild extends RawCloudEntity {
-
- private static CloudBuild.CreatedBy parseCreatedBy(Build buildResource) {
- CreatedBy createdBy = buildResource.getCreatedBy();
- return ImmutableCreatedBy.builder()
- .guid(parseNullableGuid(createdBy.getId()))
- .name(createdBy.getName())
- .build();
- }
-
- private static CloudBuild.PackageInfo parsePackageInfo(Build buildResource) {
- Relationship packageRelationship = buildResource.getInputPackage();
- String packageId = packageRelationship.getId();
- return ImmutablePackageInfo.of(parseNullableGuid(packageId));
- }
-
- private static DropletInfo parseDropletInfo(Build buildResource) {
- Droplet droplet = buildResource.getDroplet();
- return Optional.ofNullable(droplet)
- .map(Droplet::getId)
- .map(RawCloudEntity::parseNullableGuid)
- .map(dropletGuid -> ImmutableDropletInfo.builder()
- .guid(dropletGuid)
- .build())
- .orElse(null);
- }
-
- private static CloudBuild.State parseState(BuildState state) {
- return parseEnum(state, CloudBuild.State.class);
- }
-
- @Value.Parameter
- public abstract Build getResource();
-
- @Override
- public CloudBuild derive() {
- Build resource = getResource();
- return ImmutableCloudBuild.builder()
- .metadata(parseResourceMetadata(resource))
- .createdBy(parseCreatedBy(resource))
- .packageInfo(parsePackageInfo(resource))
- .dropletInfo(parseDropletInfo(resource))
- .state(parseState(resource.getState()))
- .error(resource.getError())
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudDomain.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudDomain.java
deleted file mode 100644
index f03981dbaa..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudDomain.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.client.v3.domains.Domain;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudDomain;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudDomain;
-
-@Value.Immutable
-public abstract class RawCloudDomain extends RawCloudEntity {
-
- @Value.Parameter
- public abstract Domain getResource();
-
- @Override
- public CloudDomain derive() {
- Domain resource = getResource();
- return ImmutableCloudDomain.builder()
- .metadata(parseResourceMetadata(resource))
- .name(resource.getName())
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudEntity.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudEntity.java
deleted file mode 100644
index 537b1260e2..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudEntity.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.text.MessageFormat;
-import java.time.LocalDateTime;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeParseException;
-import java.util.Collection;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-import org.cloudfoundry.client.v3.Resource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudMetadata;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Derivable;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudMetadata;
-
-public abstract class RawCloudEntity implements Derivable {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(RawCloudEntity.class);
-
- protected RawCloudEntity() {
- // Recommended by Sonar.
- }
-
- public static CloudMetadata parseResourceMetadata(Resource resource) {
- return ImmutableCloudMetadata.builder()
- .guid(parseNullableGuid(resource.getId()))
- .createdAt(parseNullableDate(resource.getCreatedAt()))
- .updatedAt(parseNullableDate(resource.getUpdatedAt()))
- .build();
- }
-
- protected static UUID parseNullableGuid(String guid) {
- return guid == null ? null : parseGuid(guid);
- }
-
- protected static UUID parseGuid(String guid) {
- try {
- return UUID.fromString(guid);
- } catch (IllegalArgumentException e) {
- LOGGER.warn(MessageFormat.format("Could not parse GUID string: \"{0}\"", guid), e);
- return null;
- }
- }
-
- protected static LocalDateTime parseNullableDate(String date) {
- return date == null ? null : parseDate(date);
- }
-
- protected static LocalDateTime parseDate(String dateString) {
- try {
- return ZonedDateTime.parse(dateString, DateTimeFormatter.ISO_DATE_TIME)
- .toLocalDateTime();
- } catch (DateTimeParseException e) {
- LOGGER.warn(MessageFormat.format("Could not parse date string: \"{0}\"", dateString), e);
- return null;
- }
- }
-
- protected static > E parseEnum(Enum> value, Class targetEnum) {
- String name = value.name()
- .toUpperCase();
- return Enum.valueOf(targetEnum, name);
- }
-
- protected static D deriveFromNullable(Derivable derivable) {
- return derivable == null ? null : derivable.derive();
- }
-
- protected static Collection derive(Collection> derivables) {
- return derivables.stream()
- .map(Derivable::derive)
- .collect(Collectors.toList());
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudEvent.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudEvent.java
deleted file mode 100644
index 7a0937f970..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudEvent.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.client.v3.auditevents.AuditEventActor;
-import org.cloudfoundry.client.v3.auditevents.AuditEventResource;
-import org.cloudfoundry.client.v3.auditevents.AuditEventTarget;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudEvent;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudEvent.Participant;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudEvent;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudEvent.ImmutableParticipant;
-
-@Value.Immutable
-public abstract class RawCloudEvent extends RawCloudEntity {
-
- @Value.Parameter
- public abstract AuditEventResource getResource();
-
- @Override
- public CloudEvent derive() {
- AuditEventResource resource = getResource();
- return ImmutableCloudEvent.builder()
- .metadata(parseResourceMetadata(resource))
- .target(parseTarget(resource))
- .actor(parseActor(resource))
- .type(resource.getType())
- .build();
- }
-
- private static Participant parseTarget(AuditEventResource resource) {
- AuditEventTarget target = resource.getAuditEventTarget();
- if (target == null) {
- return ImmutableParticipant.builder()
- .build();
- }
- return ImmutableParticipant.builder()
- .guid(parseNullableGuid(target.getId()))
- .name(target.getName())
- .type(target.getType())
- .build();
- }
-
- private static Participant parseActor(AuditEventResource resource) {
- AuditEventActor actor = resource.getAuditEventActor();
- if (actor == null) {
- return ImmutableParticipant.builder()
- .build();
- }
- return ImmutableParticipant.builder()
- .guid(parseNullableGuid(actor.getId()))
- .name(actor.getName())
- .type(actor.getType())
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudPackage.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudPackage.java
deleted file mode 100644
index 73933bf781..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudPackage.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.client.v3.Checksum;
-import org.cloudfoundry.client.v3.packages.BitsData;
-import org.cloudfoundry.client.v3.packages.DockerData;
-import org.cloudfoundry.client.v3.packages.Package;
-import org.cloudfoundry.client.v3.packages.PackageType;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudPackage;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableBitsData;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudPackage;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableDockerData;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Status;
-
-@Value.Immutable
-public abstract class RawCloudPackage extends RawCloudEntity {
-
- @Value.Parameter
- public abstract Package getResource();
-
- @Override
- public CloudPackage derive() {
- Package resource = getResource();
- return ImmutableCloudPackage.builder()
- .metadata(parseResourceMetadata(resource))
- .status(parseStatus(resource))
- .data(parseData(resource))
- .type(parseType(resource))
- .build();
- }
-
- private static Status parseStatus(Package resource) {
- return parseEnum(resource.getState(), Status.class);
- }
-
- private static CloudPackage.PackageData parseData(Package resource) {
- if (resource.getType() == PackageType.BITS) {
- return parseBitsData((BitsData) resource.getData());
- }
- return parseDockerData((DockerData) resource.getData());
- }
-
- private static CloudPackage.PackageData parseBitsData(BitsData data) {
- return ImmutableBitsData.builder()
- .checksum(parseBitsChecksum(data.getChecksum()))
- .error(data.getError())
- .build();
- }
-
- private static org.cloudfoundry.multiapps.controller.client.facade.domain.BitsData.Checksum parseBitsChecksum(Checksum checksum) {
- if (checksum == null) {
- return null;
- }
- return ImmutableBitsData.ImmutableChecksum.builder()
- .algorithm(checksum.getType()
- .toString())
- .value(checksum.getValue())
- .build();
- }
-
- private static CloudPackage.PackageData parseDockerData(DockerData data) {
- return ImmutableDockerData.builder()
- .image(data.getImage())
- .username(data.getUsername())
- .password(data.getPassword())
- .build();
- }
-
- private static CloudPackage.Type parseType(Package resource) {
- return parseEnum(resource.getType(), CloudPackage.Type.class);
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudProcess.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudProcess.java
deleted file mode 100644
index 931f528b75..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudProcess.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.client.v3.processes.Data;
-import org.cloudfoundry.client.v3.processes.HealthCheck;
-import org.cloudfoundry.client.v3.processes.Process;
-import org.cloudfoundry.client.v3.processes.ReadinessHealthCheck;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudProcess;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.HealthCheckType;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudProcess;
-import org.immutables.value.Value;
-
-@Value.Immutable
-public abstract class RawCloudProcess extends RawCloudEntity {
-
- @Value.Parameter
- public abstract Process getProcess();
-
- @Override
- public CloudProcess derive() {
- Process process = getProcess();
- HealthCheck healthCheck = process.getHealthCheck();
- ReadinessHealthCheck readinessHealthCheckType = process.getReadinessHealthCheck();
- Integer healthCheckTimeout = null;
- String healthCheckHttpEndpoint = null;
- Integer healthCheckInvocationTimeout = null;
- Integer healthCheckInterval = null;
- if (healthCheck.getData() != null) {
- Data healthCheckData = healthCheck.getData();
- healthCheckTimeout = healthCheckData.getTimeout();
- healthCheckInvocationTimeout = healthCheckData.getInvocationTimeout();
- healthCheckHttpEndpoint = healthCheckData.getEndpoint();
- healthCheckInterval = healthCheckData.getInterval();
- }
- Integer readinessHealthCheckInvocationTimeout = null;
- String readinessHealthCheckHttpEndpoint = null;
- Integer readinessHealthCheckInterval = null;
- if (readinessHealthCheckType.getData() != null) {
- Data readinessHealthCheckData = readinessHealthCheckType.getData();
- readinessHealthCheckInvocationTimeout = readinessHealthCheckData.getInvocationTimeout();
- readinessHealthCheckHttpEndpoint = readinessHealthCheckData.getEndpoint();
- readinessHealthCheckInterval = readinessHealthCheckData.getInterval();
- }
- return ImmutableCloudProcess.builder()
- .command(process.getCommand())
- .instances(process.getInstances())
- .memoryInMb(process.getMemoryInMb())
- .diskInMb(process.getDiskInMb())
- .healthCheckType(HealthCheckType.valueOf(healthCheck.getType()
- .getValue()
- .toUpperCase()))
- .healthCheckHttpEndpoint(healthCheckHttpEndpoint)
- .healthCheckTimeout(healthCheckTimeout)
- .healthCheckInvocationTimeout(healthCheckInvocationTimeout)
- .healthCheckInterval(healthCheckInterval)
- .readinessHealthCheckType(readinessHealthCheckType.getType()
- .getValue())
- .readinessHealthCheckHttpEndpoint(readinessHealthCheckHttpEndpoint)
- .readinessHealthCheckInvocationTimeout(readinessHealthCheckInvocationTimeout)
- .readinessHealthCheckInterval(readinessHealthCheckInterval)
- .build();
- }
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceBinding.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceBinding.java
deleted file mode 100644
index ab9ba4cad8..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceBinding.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.UUID;
-
-import org.cloudfoundry.client.v3.servicebindings.ServiceBinding;
-import org.cloudfoundry.client.v3.servicebindings.ServiceBindingResource;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceBinding;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServiceBinding;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ServiceCredentialBindingOperation;
-
-@Value.Immutable
-public abstract class RawCloudServiceBinding extends RawCloudEntity {
-
- @Value.Parameter
- public abstract ServiceBindingResource getServiceBinding();
-
- @Override
- public CloudServiceBinding derive() {
- ServiceBinding serviceBinding = getServiceBinding();
- var appRelationship = serviceBinding.getRelationships()
- .getApplication();
- return ImmutableCloudServiceBinding.builder()
- .metadata(parseResourceMetadata(serviceBinding))
- .applicationGuid(parseNullableGuid(appRelationship == null ? null
- : appRelationship.getData()
- .getId()))
- .serviceInstanceGuid(UUID.fromString(serviceBinding.getRelationships()
- .getServiceInstance()
- .getData()
- .getId()))
- .serviceBindingOperation(ServiceCredentialBindingOperation.from(getServiceBinding().getLastOperation()))
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceBroker.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceBroker.java
deleted file mode 100644
index d76fcc5cdd..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceBroker.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.Optional;
-
-import org.cloudfoundry.client.v3.Relationship;
-import org.cloudfoundry.client.v3.ToOneRelationship;
-import org.cloudfoundry.client.v3.servicebrokers.ServiceBroker;
-import org.cloudfoundry.client.v3.servicebrokers.ServiceBrokerRelationships;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceBroker;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServiceBroker;
-
-@Value.Immutable
-public abstract class RawCloudServiceBroker extends RawCloudEntity {
-
- @Value.Parameter
- public abstract ServiceBroker getServiceBroker();
-
- @Override
- public CloudServiceBroker derive() {
- ServiceBroker serviceBroker = getServiceBroker();
- String spaceGuid = getSpaceGuid(serviceBroker);
- return ImmutableCloudServiceBroker.builder()
- .metadata(parseResourceMetadata(serviceBroker))
- .name(serviceBroker.getName())
- .url(serviceBroker.getUrl())
- .spaceGuid(spaceGuid)
- .build();
- }
-
- private String getSpaceGuid(ServiceBroker serviceBroker) {
- return Optional.ofNullable(serviceBroker.getRelationships())
- .map(ServiceBrokerRelationships::getSpace)
- .map(ToOneRelationship::getData)
- .map(Relationship::getId)
- .orElse(null);
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceInstance.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceInstance.java
deleted file mode 100644
index af4d58b936..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceInstance.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.Optional;
-
-import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceResource;
-import org.cloudfoundry.client.v3.serviceofferings.ServiceOffering;
-import org.cloudfoundry.client.v3.serviceplans.ServicePlan;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.Nullable;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceInstance;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServiceInstance;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ServiceOperation;
-
-@Value.Immutable
-public abstract class RawCloudServiceInstance extends RawCloudEntity {
-
- @Value.Parameter
- public abstract ServiceInstanceResource getResource();
-
- @Nullable
- public abstract ServicePlan getServicePlan();
-
- @Nullable
- public abstract ServiceOffering getServiceOffering();
-
- @Override
- public CloudServiceInstance derive() {
- ServiceInstanceResource resource = getResource();
- return ImmutableCloudServiceInstance.builder()
- .metadata(parseResourceMetadata(resource))
- .v3Metadata(resource.getMetadata())
- .name(resource.getName())
- .plan(getServicePlanName())
- .label(getLabelName())
- .type(resource.getType())
- .tags(resource.getTags())
- .lastOperation(ServiceOperation.fromLastOperation(resource.getLastOperation()))
- .syslogDrainUrl(resource.getSyslogDrainUrl())
- .build();
- }
-
- private String getServicePlanName() {
- return Optional.ofNullable(getServicePlan())
- .map(ServicePlan::getName)
- .orElse(null);
- }
-
- private String getLabelName() {
- return Optional.ofNullable(getServiceOffering())
- .map(ServiceOffering::getName)
- .orElse(null);
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceKey.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceKey.java
deleted file mode 100644
index 97f6e8eb31..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceKey.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.Map;
-
-import org.cloudfoundry.AllowNulls;
-import org.cloudfoundry.client.v3.servicebindings.ServiceBindingResource;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.Nullable;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceInstance;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceKey;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Derivable;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServiceKey;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ServiceCredentialBindingOperation;
-
-@Value.Immutable
-public abstract class RawCloudServiceKey extends RawCloudEntity {
-
- public abstract ServiceBindingResource getServiceBindingResource();
-
- @Nullable
- @AllowNulls
- public abstract Map getCredentials();
-
- public abstract Derivable getServiceInstance();
-
- @Override
- public CloudServiceKey derive() {
- ServiceBindingResource serviceBindingResource = getServiceBindingResource();
- Derivable serviceInstance = getServiceInstance();
- return ImmutableCloudServiceKey.builder()
- .metadata(parseResourceMetadata(serviceBindingResource))
- .v3Metadata(serviceBindingResource.getMetadata())
- .name(serviceBindingResource.getName())
- .credentials(getCredentials())
- .serviceInstance(serviceInstance.derive())
- .serviceKeyOperation(ServiceCredentialBindingOperation.from(serviceBindingResource.getLastOperation()))
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceOffering.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceOffering.java
deleted file mode 100644
index c252aa50bd..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServiceOffering.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.List;
-
-import org.cloudfoundry.client.v3.serviceofferings.ServiceOfferingResource;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceOffering;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServicePlan;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Derivable;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServiceOffering;
-
-@Value.Immutable
-public abstract class RawCloudServiceOffering extends RawCloudEntity {
-
- public abstract ServiceOfferingResource getServiceOffering();
-
- public abstract List> getServicePlans();
-
- @Override
- public CloudServiceOffering derive() {
- ServiceOfferingResource serviceOffering = getServiceOffering();
- return ImmutableCloudServiceOffering.builder()
- .metadata(parseResourceMetadata(serviceOffering))
- .name(serviceOffering.getName())
- .isAvailable(serviceOffering.getAvailable())
- .isBindable(serviceOffering.getBrokerCatalog()
- .getFeatures()
- .getBindable())
- .description(serviceOffering.getDescription())
- .isShareable(serviceOffering.getShareable())
- .extra(serviceOffering.getBrokerCatalog()
- .getMetadata())
- .docUrl(serviceOffering.getDocumentationUrl())
- .brokerId(serviceOffering.getRelationships()
- .getServiceBroker()
- .getData()
- .getId())
- .uniqueId(serviceOffering.getBrokerCatalog()
- .getBrokerCatalogId())
- .servicePlans(derive(getServicePlans()))
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServicePlan.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServicePlan.java
deleted file mode 100644
index a79527037e..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudServicePlan.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.client.v3.serviceplans.ServicePlan;
-import org.cloudfoundry.client.v3.serviceplans.Visibility;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServicePlan;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServicePlan;
-
-@Value.Immutable
-public abstract class RawCloudServicePlan extends RawCloudEntity {
-
- @Value.Parameter
- public abstract ServicePlan getResource();
-
- @Override
- public CloudServicePlan derive() {
- ServicePlan resource = getResource();
- return ImmutableCloudServicePlan.builder()
- .metadata(parseResourceMetadata(resource))
- .name(resource.getName())
- .description(resource.getDescription())
- .extra(resource.getBrokerCatalog()
- .getMetadata())
- .uniqueId(resource.getBrokerCatalog()
- .getBrokerCatalogId())
- .serviceOfferingId(resource.getRelationships()
- .getServiceOffering()
- .getData()
- .getId())
- .isPublic(resource.getVisibilityType()
- .equals(Visibility.PUBLIC))
- .isFree(resource.getFree())
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudStack.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudStack.java
deleted file mode 100644
index 6c2a8ce152..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudStack.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.client.v3.stacks.Stack;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudStack;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudStack;
-
-@Value.Immutable
-public abstract class RawCloudStack extends RawCloudEntity {
-
- @Value.Parameter
- public abstract Stack getStack();
-
- @Override
- public CloudStack derive() {
- Stack stack = getStack();
- return ImmutableCloudStack.builder()
- .metadata(parseResourceMetadata(stack))
- .name(stack.getName())
- .description(stack.getDescription())
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudTask.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudTask.java
deleted file mode 100644
index b963d4457a..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawCloudTask.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import java.util.Optional;
-
-import org.cloudfoundry.client.v3.tasks.Result;
-import org.cloudfoundry.client.v3.tasks.Task;
-import org.cloudfoundry.client.v3.tasks.TaskState;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudTask;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudTask;
-
-@Value.Immutable
-public abstract class RawCloudTask extends RawCloudEntity {
-
- @Value.Parameter
- public abstract Task getResource();
-
- @Override
- public CloudTask derive() {
- Task resource = getResource();
- return ImmutableCloudTask.builder()
- .metadata(parseResourceMetadata(resource))
- .name(resource.getName())
- .command(resource.getCommand())
- .limits(parseLimits(resource))
- .result(parseResult(resource))
- .state(parseState(resource.getState()))
- .build();
- }
-
- private static CloudTask.Result parseResult(Task resource) {
- return Optional.ofNullable(resource.getResult())
- .map(Result::getFailureReason)
- .map(ImmutableCloudTask.ImmutableResult::of)
- .orElse(null);
- }
-
- private static CloudTask.Limits parseLimits(Task resource) {
- return ImmutableCloudTask.ImmutableLimits.builder()
- .disk(resource.getDiskInMb())
- .memory(resource.getMemoryInMb())
- .build();
- }
-
- private static CloudTask.State parseState(TaskState state) {
- return parseEnum(state, CloudTask.State.class);
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawUserRole.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawUserRole.java
deleted file mode 100644
index 8eacc03f55..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawUserRole.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Derivable;
-import org.cloudfoundry.client.v3.roles.RoleResource;
-import org.immutables.value.Value;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.UserRole;
-
-@Value.Immutable
-public abstract class RawUserRole implements Derivable {
-
- @Value.Parameter
- public abstract RoleResource getRoleResource();
-
- @Override
- public UserRole derive() {
- RoleResource role = getRoleResource();
- return UserRole.fromRoleType(role.getType());
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawV3CloudServiceInstance.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawV3CloudServiceInstance.java
deleted file mode 100644
index 8155a4ad41..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/adapters/RawV3CloudServiceInstance.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.adapters;
-
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceInstance;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServiceInstance;
-import org.cloudfoundry.client.v3.serviceinstances.ServiceInstance;
-import org.immutables.value.Value;
-
-@Value.Immutable
-public abstract class RawV3CloudServiceInstance extends RawCloudEntity {
-
- @Value.Parameter
- public abstract ServiceInstance getServiceInstance();
-
- @Override
- public CloudServiceInstance derive() {
- ServiceInstance serviceInstance = getServiceInstance();
- return ImmutableCloudServiceInstance.builder()
- .metadata(parseResourceMetadata(serviceInstance))
- .v3Metadata(serviceInstance.getMetadata())
- .name(serviceInstance.getName())
- .tags(serviceInstance.getTags())
- .build();
- }
-
-}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudAsyncJob.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudAsyncJob.java
index 394a40c3b7..20b52febc8 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudAsyncJob.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudAsyncJob.java
@@ -1,6 +1,5 @@
package org.cloudfoundry.multiapps.controller.client.facade.domain;
-import org.cloudfoundry.client.v3.jobs.JobState;
import org.immutables.value.Value;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudEntity.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudEntity.java
index 16bf0aef9b..aef922d829 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudEntity.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudEntity.java
@@ -2,7 +2,7 @@
import java.util.UUID;
-import org.cloudfoundry.client.v3.Metadata;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.Metadata;
import org.cloudfoundry.multiapps.controller.client.facade.Nullable;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceBinding.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceBinding.java
index bceb94223b..e3fb8544fe 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceBinding.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceBinding.java
@@ -2,7 +2,7 @@
import java.util.UUID;
-import org.cloudfoundry.Nullable;
+import org.cloudfoundry.multiapps.controller.client.facade.Nullable;
import org.immutables.value.Value;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceInstance.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceInstance.java
index 78db202828..2cf5216efa 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceInstance.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceInstance.java
@@ -3,8 +3,7 @@
import java.util.List;
import java.util.Map;
-import org.cloudfoundry.AllowNulls;
-import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceType;
+import org.cloudfoundry.multiapps.controller.client.facade.AllowNulls;
import org.immutables.value.Value;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceKey.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceKey.java
index a77cad1967..76c211eeda 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceKey.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/CloudServiceKey.java
@@ -2,7 +2,7 @@
import java.util.Map;
-import org.cloudfoundry.AllowNulls;
+import org.cloudfoundry.multiapps.controller.client.facade.AllowNulls;
import org.immutables.value.Value;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/HealthCheckType.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/HealthCheckType.java
index 6cd1a86842..992fa758a3 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/HealthCheckType.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/HealthCheckType.java
@@ -3,8 +3,13 @@
public enum HealthCheckType {
HTTP, PORT, PROCESS, @Deprecated NONE;
+ public String getValue() {
+ return name().toLowerCase();
+ }
+
@Override
public String toString() {
- return this.name().toLowerCase();
+ return this.name()
+ .toLowerCase();
}
}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/InstanceState.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/InstanceState.java
index 89d88d803d..a5425130ed 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/InstanceState.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/InstanceState.java
@@ -1,16 +1,14 @@
package org.cloudfoundry.multiapps.controller.client.facade.domain;
-import org.cloudfoundry.client.v3.processes.ProcessState;
-
public enum InstanceState {
CRASHED, DOWN, RUNNING, STARTING, UNKNOWN;
-
- public static InstanceState valueOfWithDefault(ProcessState state) {
+
+ public static InstanceState valueOfWithDefault(String state) {
if (state == null) {
return UNKNOWN;
}
try {
- return InstanceState.valueOf(state.getValue());
+ return InstanceState.valueOf(state);
} catch (IllegalArgumentException e) {
return InstanceState.UNKNOWN;
}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/JobState.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/JobState.java
new file mode 100644
index 0000000000..9c3445f45a
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/JobState.java
@@ -0,0 +1,34 @@
+package org.cloudfoundry.multiapps.controller.client.facade.domain;
+
+import java.text.MessageFormat;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import org.cloudfoundry.multiapps.controller.Messages;
+
+public enum JobState {
+
+ PROCESSING("processing"), POLLING("polling"), COMPLETE("complete"), FAILED("failed");
+
+ private final String value;
+
+ JobState(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+
+ @JsonCreator
+ public static JobState from(String value) {
+ for (JobState state : values()) {
+ if (state.value.equals(value)) {
+ return state;
+ }
+ }
+
+ throw new IllegalArgumentException(MessageFormat.format(Messages.UNKNOWN_JOB_STATE_0, value));
+ }
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/LastOperation.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/LastOperation.java
new file mode 100644
index 0000000000..0e43b64c12
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/LastOperation.java
@@ -0,0 +1,4 @@
+package org.cloudfoundry.multiapps.controller.client.facade.domain;
+
+public record LastOperation(String type, String state, String description, String createdAt, String updatedAt) {
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/Lifecycle.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/Lifecycle.java
index f448f2c668..d6453dd89e 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/Lifecycle.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/Lifecycle.java
@@ -3,7 +3,7 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.cloudfoundry.multiapps.controller.client.facade.Nullable;
-import org.cloudfoundry.AllowNulls;
+import org.cloudfoundry.multiapps.controller.client.facade.AllowNulls;
import org.immutables.value.Value;
import java.util.Map;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/Metadata.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/Metadata.java
new file mode 100644
index 0000000000..342e1d2d44
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/Metadata.java
@@ -0,0 +1,115 @@
+package org.cloudfoundry.multiapps.controller.client.facade.domain;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public final class Metadata {
+
+ private final Map labels;
+ private final Map annotations;
+
+ @JsonCreator
+ Metadata(@JsonProperty("labels") Map labels, @JsonProperty("annotations") Map annotations) {
+ this.labels = labels == null ? Collections.emptyMap() : Collections.unmodifiableMap(new LinkedHashMap<>(labels));
+ this.annotations = annotations == null ? Collections.emptyMap() : Collections.unmodifiableMap(new LinkedHashMap<>(annotations));
+ }
+
+ @JsonProperty("labels")
+ public Map getLabels() {
+ return labels;
+ }
+
+ @JsonProperty("annotations")
+ public Map getAnnotations() {
+ return annotations;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Metadata metadata = (Metadata) o;
+ return labels.equals(metadata.labels) && annotations.equals(metadata.annotations);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(labels, annotations);
+ }
+
+ @Override
+ public String toString() {
+ return "Metadata{annotations=" + annotations + ", labels=" + labels + "}";
+ }
+
+ public static final class Builder {
+
+ private final Map labels = new LinkedHashMap<>();
+ private final Map annotations = new LinkedHashMap<>();
+
+ private Builder() {
+ }
+
+ public Builder from(Metadata metadata) {
+ if (metadata != null) {
+ this.labels.putAll(metadata.getLabels());
+ this.annotations.putAll(metadata.getAnnotations());
+ }
+
+ return this;
+ }
+
+ public Builder label(String key, String value) {
+ this.labels.put(key, value);
+ return this;
+ }
+
+ public Builder labels(Map labels) {
+ if (labels != null) {
+ this.labels.putAll(labels);
+ }
+
+ return this;
+ }
+
+ public Builder putAllLabels(Map labels) {
+ return labels(labels);
+ }
+
+ public Builder annotation(String key, String value) {
+ this.annotations.put(key, value);
+ return this;
+ }
+
+ public Builder annotations(Map annotations) {
+ if (annotations != null) {
+ this.annotations.putAll(annotations);
+ }
+
+ return this;
+ }
+
+ public Builder putAllAnnotations(Map annotations) {
+ return annotations(annotations);
+ }
+
+ public Metadata build() {
+ return new Metadata(labels, annotations);
+ }
+ }
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceCredentialBindingOperation.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceCredentialBindingOperation.java
index 4f202834cc..73403202f1 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceCredentialBindingOperation.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceCredentialBindingOperation.java
@@ -5,12 +5,10 @@
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
-import org.cloudfoundry.client.v3.LastOperation;
-import org.immutables.value.Value;
-
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.cloudfoundry.multiapps.controller.client.facade.Nullable;
+import org.immutables.value.Value;
@Value.Immutable
@JsonSerialize(as = ImmutableServiceCredentialBindingOperation.class)
@@ -31,11 +29,12 @@ public abstract class ServiceCredentialBindingOperation {
public abstract LocalDateTime getUpdatedAt();
public static ServiceCredentialBindingOperation from(LastOperation lastOperation) {
- String lastOperationType = lastOperation.getType();
- String lastOperationState = lastOperation.getState();
- String lastOperationDescription = lastOperation.getDescription();
- String lastOperationCreatedAt = lastOperation.getCreatedAt();
- String lastOperationUpdatedAt = lastOperation.getUpdatedAt();
+ String lastOperationType = lastOperation.type();
+ String lastOperationState = lastOperation.state();
+ String lastOperationDescription = lastOperation.description();
+ String lastOperationCreatedAt = lastOperation.createdAt();
+ String lastOperationUpdatedAt = lastOperation.updatedAt();
+
return ImmutableServiceCredentialBindingOperation.builder()
.type(ServiceCredentialBindingOperation.Type.fromString(lastOperationType))
.state(ServiceCredentialBindingOperation.State.fromString(lastOperationState))
@@ -55,8 +54,9 @@ public static Type fromString(String value) {
.filter(type -> type.toString()
.equals(value))
.findFirst()
- .orElseThrow(() -> new IllegalArgumentException(MessageFormat.format("Illegal service binding operation type: \"{0}\"",
- value)));
+ .orElseThrow(
+ () -> new IllegalArgumentException(MessageFormat.format("Illegal service binding operation type: \"{0}\"",
+ value)));
}
@Override
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceInstanceType.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceInstanceType.java
new file mode 100644
index 0000000000..434443b306
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceInstanceType.java
@@ -0,0 +1,34 @@
+package org.cloudfoundry.multiapps.controller.client.facade.domain;
+
+import java.text.MessageFormat;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import org.cloudfoundry.multiapps.controller.Messages;
+
+public enum ServiceInstanceType {
+
+ MANAGED("managed"), USER_PROVIDED("user-provided");
+
+ private final String value;
+
+ ServiceInstanceType(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+
+ @JsonCreator
+ public static ServiceInstanceType from(String value) {
+ for (ServiceInstanceType type : values()) {
+ if (type.value.equals(value)) {
+ return type;
+ }
+ }
+
+ throw new IllegalArgumentException(MessageFormat.format(Messages.UNKNOWN_SERVICE_INSTANCE_TYPE_0, value));
+ }
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceOperation.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceOperation.java
index 151dae6bfa..7edff81be7 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceOperation.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/ServiceOperation.java
@@ -3,8 +3,6 @@
import java.text.MessageFormat;
import java.util.Objects;
-import org.cloudfoundry.client.v3.LastOperation;
-
public class ServiceOperation {
public enum Type {
@@ -82,13 +80,14 @@ public State getState() {
}
public static ServiceOperation fromLastOperation(LastOperation lastOperation) {
- if (lastOperation == null || lastOperation.getType() == null || lastOperation.getState() == null) {
+ if (lastOperation == null || lastOperation.type() == null || lastOperation.state() == null) {
return null;
}
- Type type = Type.fromString(lastOperation.getType());
- State state = State.fromString(lastOperation.getState());
- String description = lastOperation.getDescription();
- return new ServiceOperation(type, description, state);
+
+ Type operationType = Type.fromString(lastOperation.type());
+ State operationState = State.fromString(lastOperation.state());
+ String operationDescription = lastOperation.description();
+ return new ServiceOperation(operationType, operationDescription, operationState);
}
@Override
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/UserRole.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/UserRole.java
index 3ee5e84386..8644a5cdf2 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/UserRole.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/domain/UserRole.java
@@ -1,10 +1,11 @@
package org.cloudfoundry.multiapps.controller.client.facade.domain;
+import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
-import org.cloudfoundry.client.v3.roles.RoleType;
+import org.cloudfoundry.multiapps.controller.Messages;
public enum UserRole {
@@ -18,13 +19,15 @@ public enum UserRole {
private static final Map NAMES_TO_VALUES = Arrays.stream(values())
.collect(Collectors.toMap(UserRole::getName,
- roleType -> roleType));
+ roleType -> roleType));
+
+ public static UserRole fromRoleType(String roleTypeValue) {
+ UserRole userRole = NAMES_TO_VALUES.get(roleTypeValue);
- public static UserRole fromRoleType(RoleType roleType) {
- UserRole userRole = NAMES_TO_VALUES.get(roleType.getValue());
if (userRole == null) {
- throw new IllegalArgumentException("Unknown user role: " + roleType.getValue());
+ throw new IllegalArgumentException(MessageFormat.format(Messages.UNKNOWN_USER_ROLE_0, roleTypeValue));
}
+
return userRole;
}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/dto/ApplicationToCreateDto.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/dto/ApplicationToCreateDto.java
index e23244f2f4..c32aa17139 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/dto/ApplicationToCreateDto.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/dto/ApplicationToCreateDto.java
@@ -3,7 +3,7 @@
import java.util.Map;
import java.util.Set;
-import org.cloudfoundry.client.v3.Metadata;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.Metadata;
import org.immutables.value.Value;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/oauth2/OAuthClient.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/oauth2/OAuthClient.java
index 414fc822b8..03ae12365f 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/oauth2/OAuthClient.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/oauth2/OAuthClient.java
@@ -8,9 +8,7 @@
import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials;
import org.cloudfoundry.multiapps.controller.client.facade.Constants;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.OAuthTokenProvider;
import org.cloudfoundry.multiapps.controller.client.facade.util.JsonUtil;
-import org.cloudfoundry.reactor.TokenProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
@@ -78,10 +76,6 @@ public String getAuthorizationHeaderValue() {
return null;
}
- public TokenProvider getTokenProvider() {
- return new OAuthTokenProvider(this);
- }
-
private boolean shouldRefreshToken() {
return credentials.isRefreshable() && token.getOAuth2AccessToken()
.getExpiresAt()
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/ApplicationsV3Operations.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/ApplicationsV3Operations.java
new file mode 100644
index 0000000000..12a19a3b8b
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/ApplicationsV3Operations.java
@@ -0,0 +1,268 @@
+package org.cloudfoundry.multiapps.controller.client.facade.rest;
+
+import java.text.MessageFormat;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.cloudfoundry.multiapps.controller.Messages;
+import org.cloudfoundry.multiapps.controller.client.facade.CloudOperationException;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudApplication;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudSpace;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.Metadata;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.Staging;
+import org.cloudfoundry.multiapps.controller.client.facade.dto.ApplicationToCreateDto;
+import org.cloudfoundry.multiapps.controller.client.facade.rest.resources.V3Application;
+import org.cloudfoundry.multiapps.controller.client.facade.rest.resources.V3ApplicationMapper;
+import org.cloudfoundry.multiapps.controller.client.facade.rest.resources.V3ListResponse;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpStatus;
+
+public class ApplicationsV3Operations {
+
+ private static final ParameterizedTypeReference> APPLICATION_PAGE = new ParameterizedTypeReference<>() {
+ };
+
+ private static final Duration DELETE_JOB_TIMEOUT = Duration.ofMinutes(5);
+
+ private final CloudControllerV3Client cc;
+ private final CloudSpace target;
+
+ public ApplicationsV3Operations(CloudControllerV3Client cc, CloudSpace target) {
+ this.cc = cc;
+ this.target = target;
+ }
+
+ public UUID createApplication(ApplicationToCreateDto dto) {
+ if (target == null || target.getGuid() == null) {
+ throw new CloudOperationException(HttpStatus.BAD_REQUEST, Messages.BAD_REQUEST,
+ Messages.TARGET_SPACE_REQUIRED_TO_CREATE_AN_APPLICATION);
+ }
+ Map body = new HashMap<>();
+ body.put("name", dto.getName());
+ body.put("lifecycle", buildLifecycle(dto.getStaging()));
+ body.put("relationships", Map.of("space", Map.of("data", Map.of("guid", target.getGuid()
+ .toString()))));
+ if (dto.getEnv() != null) {
+ body.put("environment_variables", dto.getEnv());
+ }
+ if (dto.getMetadata() != null) {
+ body.put("metadata", Map.of("labels", dto.getMetadata()
+ .getLabels(),
+ "annotations", dto.getMetadata()
+ .getAnnotations()));
+ }
+ V3Application created = cc.getRestClient()
+ .post()
+ .uri(CloudControllerV3Endpoints.APPS)
+ .body(body)
+ .retrieve()
+ .body(V3Application.class);
+ UUID appGuid = UUID.fromString(created.guid());
+ Map scale = new HashMap<>();
+ if (dto.getMemoryInMb() != null) {
+ scale.put("memory_in_mb", dto.getMemoryInMb());
+ }
+ if (dto.getDiskQuotaInMb() != null) {
+ scale.put("disk_in_mb", dto.getDiskQuotaInMb());
+ }
+ if (!scale.isEmpty()) {
+ scaleWebProcess(appGuid, scale);
+ }
+ return appGuid;
+ }
+
+ private Map buildLifecycle(Staging staging) {
+ if (staging == null) {
+ return Map.of("type", "buildpack", "data", Map.of());
+ }
+ if (staging.getDockerInfo() != null) {
+ return Map.of("type", "docker", "data", Map.of());
+ }
+ String type = staging.getLifecycleType() != null ? staging.getLifecycleType()
+ .name()
+ .toLowerCase()
+ : "buildpack";
+ Map data = new HashMap<>();
+ if (staging.getBuildpacks() != null) {
+ data.put("buildpacks", staging.getBuildpacks());
+ }
+ if (staging.getStackName() != null) {
+ data.put("stack", staging.getStackName());
+ }
+ return Map.of("type", type, "data", data);
+ }
+
+ public void deleteApplication(String applicationName) {
+ UUID applicationGuid = getApplicationGuid(applicationName);
+ var response = cc.getRestClient()
+ .delete()
+ .uri(CloudControllerV3Endpoints.APP_BY_GUID, applicationGuid)
+ .retrieve()
+ .toBodilessEntity();
+ cc.followAsyncJob(response, DELETE_JOB_TIMEOUT);
+ }
+
+ public CloudApplication getApplication(String applicationName) {
+ return getApplication(applicationName, true);
+ }
+
+ public CloudApplication getApplication(String applicationName, boolean required) {
+ V3Application app = findApplicationByName(applicationName);
+ if (app == null) {
+ if (required) {
+ throw new CloudOperationException(HttpStatus.NOT_FOUND, Messages.NOT_FOUND,
+ MessageFormat.format(Messages.APPLICATION_0_NOT_FOUND, applicationName));
+ }
+ return null;
+ }
+ return V3ApplicationMapper.toCloudApplication(app, target);
+ }
+
+ public UUID getApplicationGuid(String applicationName) {
+ return getApplication(applicationName).getGuid();
+ }
+
+ public String getApplicationName(UUID applicationGuid) {
+ V3Application app = cc.get(CloudControllerV3Endpoints.APPS + "/" + applicationGuid, V3Application.class);
+ return app == null ? null : app.name();
+ }
+
+ public Map getApplicationEnvironment(UUID applicationGuid) {
+ V3Application.V3EnvironmentVariables env = cc.get(CloudControllerV3Endpoints.APPS + "/" + applicationGuid
+ + "/environment_variables",
+ V3Application.V3EnvironmentVariables.class);
+ return env == null || env.var() == null ? Map.of() : env.var();
+ }
+
+ public Map getApplicationEnvironment(String applicationName) {
+ return getApplicationEnvironment(getApplicationGuid(applicationName));
+ }
+
+ public List getApplications() {
+ return listApplications(applicationsQuery(null)).stream()
+ .map(app -> V3ApplicationMapper.toCloudApplication(app, target))
+ .toList();
+ }
+
+ public List getApplicationsByMetadataLabelSelector(String labelSelector) {
+ String query = applicationsQuery(null);
+ if (labelSelector != null) {
+ query = query + CloudControllerV3Endpoints.AMPERSAND_LABEL_SELECTOR + labelSelector;
+ }
+ return listApplications(query).stream()
+ .map(app -> V3ApplicationMapper.toCloudApplication(app, target))
+ .toList();
+ }
+
+ public void startApplication(String applicationName) {
+ UUID guid = getApplicationGuid(applicationName);
+ cc.getRestClient()
+ .post()
+ .uri(CloudControllerV3Endpoints.APP_START, guid)
+ .retrieve()
+ .toBodilessEntity();
+ }
+
+ public void stopApplication(String applicationName) {
+ UUID guid = getApplicationGuid(applicationName);
+ cc.getRestClient()
+ .post()
+ .uri(CloudControllerV3Endpoints.APP_STOP, guid)
+ .retrieve()
+ .toBodilessEntity();
+ }
+
+ public void rename(String applicationName, String newName) {
+ UUID guid = getApplicationGuid(applicationName);
+ try {
+ cc.getRestClient()
+ .patch()
+ .uri(CloudControllerV3Endpoints.APP_BY_GUID, guid)
+ .body(Map.of("name", newName))
+ .retrieve()
+ .toBodilessEntity();
+ } catch (CloudOperationException e) {
+ //the Cloud Controller can return 503 but the rename might have happened already
+ if (e.getStatusCode() == HttpStatus.SERVICE_UNAVAILABLE && newName.equals(getApplicationName(guid))) {
+ return;
+ }
+ throw e;
+ }
+ }
+
+ public void updateApplicationInstances(String applicationName, int instances) {
+ scaleWebProcess(getApplicationGuid(applicationName), Map.of("instances", instances));
+ }
+
+ public void updateApplicationMemory(String applicationName, int memory) {
+ scaleWebProcess(getApplicationGuid(applicationName), Map.of("memory_in_mb", memory));
+ }
+
+ public void updateApplicationDiskQuota(String applicationName, int disk) {
+ scaleWebProcess(getApplicationGuid(applicationName), Map.of("disk_in_mb", disk));
+ }
+
+ public void updateApplicationEnv(String applicationName, Map env) {
+ UUID guid = getApplicationGuid(applicationName);
+ cc.getRestClient()
+ .patch()
+ .uri(CloudControllerV3Endpoints.APP_ENV_VARS, guid)
+ .body(Map.of("var", env))
+ .retrieve()
+ .toBodilessEntity();
+ }
+
+ public void bindDropletToApp(UUID dropletGuid, UUID applicationGuid) {
+ cc.getRestClient()
+ .patch()
+ .uri(CloudControllerV3Endpoints.APP_CURRENT_DROPLET, applicationGuid)
+ .body(Map.of("data", Map.of("guid", dropletGuid.toString())))
+ .retrieve()
+ .toBodilessEntity();
+ }
+
+ public void updateApplicationMetadata(UUID guid, Metadata metadata) {
+ cc.getRestClient()
+ .patch()
+ .uri(CloudControllerV3Endpoints.APP_BY_GUID, guid)
+ .body(Map.of("metadata", Map.of("labels", metadata.getLabels(), "annotations", metadata.getAnnotations())))
+ .retrieve()
+ .toBodilessEntity();
+ }
+
+ private void scaleWebProcess(UUID applicationGuid, Map scaleBody) {
+ cc.getRestClient()
+ .post()
+ .uri(CloudControllerV3Endpoints.APP_WEB_PROCESS_SCALE, applicationGuid)
+ .body(scaleBody)
+ .retrieve()
+ .toBodilessEntity();
+ }
+
+ private V3Application findApplicationByName(String applicationName) {
+ List apps = listApplications(applicationsQuery(applicationName));
+ return apps.isEmpty() ? null : apps.get(0);
+ }
+
+ private List listApplications(String query) {
+ return cc.list(query, APPLICATION_PAGE);
+ }
+
+ private String applicationsQuery(String name) {
+ StringBuilder query = new StringBuilder(CloudControllerV3Endpoints.APPS + CloudControllerV3Endpoints.QUERY_PER_PAGE
+ + CloudControllerV3Endpoints.DEFAULT_PAGE_SIZE);
+ if (target != null && target.getGuid() != null) {
+ query.append(CloudControllerV3Endpoints.AMPERSAND_SPACE_GUIDS)
+ .append(target.getGuid());
+ }
+ if (name != null) {
+ query.append(CloudControllerV3Endpoints.AMPERSAND_NAMES)
+ .append(name);
+ }
+ return query.toString();
+ }
+
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/BuildsV3Operations.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/BuildsV3Operations.java
new file mode 100644
index 0000000000..c9416c6bd0
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/BuildsV3Operations.java
@@ -0,0 +1,56 @@
+package org.cloudfoundry.multiapps.controller.client.facade.rest;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudBuild;
+import org.cloudfoundry.multiapps.controller.client.facade.rest.resources.V3Build;
+import org.cloudfoundry.multiapps.controller.client.facade.rest.resources.V3BuildMapper;
+import org.cloudfoundry.multiapps.controller.client.facade.rest.resources.V3ListResponse;
+import org.springframework.core.ParameterizedTypeReference;
+
+public class BuildsV3Operations {
+
+ private final CloudControllerV3Client cc;
+
+ public BuildsV3Operations(CloudControllerV3Client cc) {
+ this.cc = cc;
+ }
+
+ public CloudBuild createBuild(UUID packageGuid) {
+ V3Build build = cc.getRestClient()
+ .post()
+ .uri(CloudControllerV3Endpoints.BUILDS)
+ .body(Map.of("package", Map.of("guid", packageGuid.toString())))
+ .retrieve()
+ .body(V3Build.class);
+ return V3BuildMapper.toCloudBuild(build);
+ }
+
+ public CloudBuild getBuild(UUID buildGuid) {
+ V3Build build = cc.get(CloudControllerV3Endpoints.BUILDS + "/" + buildGuid, V3Build.class);
+ return V3BuildMapper.toCloudBuild(build);
+ }
+
+ public List getBuildsForApplication(UUID applicationGuid) {
+ String uri = CloudControllerV3Endpoints.APPS + "/" + applicationGuid + "/builds" + CloudControllerV3Endpoints.QUERY_PER_PAGE
+ + CloudControllerV3Endpoints.DEFAULT_PAGE_SIZE;
+ return cc.list(uri, new ParameterizedTypeReference>() {
+ })
+ .stream()
+ .map(V3BuildMapper::toCloudBuild)
+ .toList();
+ }
+
+ public List getBuildsForPackage(UUID packageGuid) {
+ String uri = CloudControllerV3Endpoints.BUILDS + CloudControllerV3Endpoints.QUERY_PACKAGE_GUIDS + packageGuid
+ + CloudControllerV3Endpoints.AMPERSAND_PER_PAGE + CloudControllerV3Endpoints.DEFAULT_PAGE_SIZE;
+ return cc.list(uri, new ParameterizedTypeReference>() {
+ })
+ .stream()
+ .map(V3BuildMapper::toCloudBuild)
+ .toList();
+ }
+
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/ClientConfigurationOptions.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/ClientConfigurationOptions.java
new file mode 100644
index 0000000000..5e9ef98e2d
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/ClientConfigurationOptions.java
@@ -0,0 +1,9 @@
+package org.cloudfoundry.multiapps.controller.client.facade.rest;
+
+import java.time.Duration;
+import java.util.Optional;
+
+public record ClientConfigurationOptions(Optional connectionTimeout, Optional responseTimeout,
+ Optional sslHandshakeTimeout, Optional connectionPoolSize,
+ Optional threadPoolSize, boolean trustSelfSignedCertificates) {
+}
\ No newline at end of file
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClient.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClient.java
index 8c79aec33e..4ed03f71d4 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClient.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClient.java
@@ -8,7 +8,7 @@
import java.util.Set;
import java.util.UUID;
-import org.cloudfoundry.client.v3.Metadata;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.Metadata;
import org.cloudfoundry.multiapps.controller.client.facade.UploadStatusCallback;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudApplication;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudAsyncJob;
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientBuilder.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientBuilder.java
new file mode 100644
index 0000000000..754b658584
--- /dev/null
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientBuilder.java
@@ -0,0 +1,181 @@
+package org.cloudfoundry.multiapps.controller.client.facade.rest;
+
+import java.net.URL;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.X509TrustManager;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.netty.channel.ChannelOption;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import org.cloudfoundry.multiapps.controller.Constants;
+import org.cloudfoundry.multiapps.controller.Messages;
+import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuthClient;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.client.ReactorClientHttpRequestFactory;
+import org.springframework.http.client.reactive.ReactorClientHttpConnector;
+import org.springframework.http.converter.ByteArrayHttpMessageConverter;
+import org.springframework.http.converter.FormHttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestClient;
+import org.springframework.web.reactive.function.client.ClientRequest;
+import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.netty.http.client.HttpClient;
+import reactor.netty.resources.ConnectionProvider;
+import reactor.netty.resources.LoopResources;
+import reactor.netty.tcp.SslProvider;
+
+public final class CloudControllerRestClientBuilder {
+
+ private CloudControllerRestClientBuilder() {
+ }
+
+ public static RestClient build(URL v3ApiUrl, OAuthClient oAuthClient, Map requestTags,
+ ClientConfigurationOptions configOptions) {
+ return buildRestClient(buildHttpClient(configOptions), v3ApiUrl, oAuthClient, requestTags);
+ }
+
+ public static RestClient buildRestClient(HttpClient httpClient, URL baseUrl, OAuthClient oAuthClient,
+ Map requestTags) {
+ return RestClient.builder()
+ .baseUrl(baseUrl.toString())
+ .requestFactory(new ReactorClientHttpRequestFactory(httpClient))
+ .messageConverters(List.of(new ByteArrayHttpMessageConverter(),
+ new StringHttpMessageConverter(),
+ new FormHttpMessageConverter(),
+ new MappingJackson2HttpMessageConverter(new ObjectMapper())))
+ .requestInterceptor((request, body, execution) -> {
+ String authorization = oAuthClient.getAuthorizationHeaderValue();
+
+ if (authorization != null) {
+ request.getHeaders()
+ .set(HttpHeaders.AUTHORIZATION, authorization);
+ }
+
+ requestTags.forEach((String key, String value) -> request.getHeaders()
+ .set(key, value));
+
+ return execution.execute(request, body);
+ })
+ .defaultStatusHandler(new CloudControllerResponseErrorHandler())
+ .build();
+ }
+
+ public static WebClient buildWebClient(HttpClient httpClient, URL baseUrl, OAuthClient oAuthClient,
+ Map requestTags) {
+ return WebClient.builder()
+ .baseUrl(baseUrl.toString())
+ .clientConnector(new ReactorClientHttpConnector(httpClient))
+ .filter(authAndTagsFilter(oAuthClient, requestTags))
+ .build();
+ }
+
+ private static ExchangeFilterFunction authAndTagsFilter(OAuthClient oAuthClient, Map requestTags) {
+ return (request, next) -> {
+ ClientRequest.Builder requestBuilder = ClientRequest.from(request);
+ String authorizationValue = oAuthClient.getAuthorizationHeaderValue();
+
+ if (authorizationValue != null) {
+ requestBuilder.header(HttpHeaders.AUTHORIZATION, authorizationValue);
+ }
+
+ requestTags.forEach((String key, String value) -> {
+ requestBuilder.header(key, value);
+ });
+
+ return next.exchange(requestBuilder.build());
+ };
+ }
+
+ static HttpClient buildHttpClient(ClientConfigurationOptions configOptions) {
+ int poolSize = configOptions.connectionPoolSize()
+ .orElse(Constants.DEFAULT_CONNECTION_POOL_SIZE);
+ ConnectionProvider connectionProvider = ConnectionProvider.builder(Constants.CONNECTION_POOL_NAME)
+ .maxConnections(poolSize)
+ .build();
+ HttpClient httpClient = HttpClient.create(connectionProvider)
+ .followRedirect(true)
+ .proxyWithSystemProperties();
+ int connectTimeoutMillis = (int) configOptions.connectionTimeout()
+ .orElse(Constants.DEFAULT_CONNECT_TIMEOUT)
+ .toMillis();
+ httpClient = httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeoutMillis);
+
+ Optional threadPoolSize = configOptions.threadPoolSize();
+ if (threadPoolSize.isPresent()) {
+ LoopResources loopResources = LoopResources.create(Constants.CONNECTION_POOL_NAME + Constants.LOOP_RESOURCES_SUFFIX,
+ threadPoolSize.get(), true);
+ httpClient = httpClient.runOn(loopResources);
+ }
+
+ Optional responseTimeout = configOptions.responseTimeout();
+ if (responseTimeout.isPresent()) {
+ httpClient = httpClient.responseTimeout(responseTimeout.get());
+ }
+
+ Optional handshakeTimeout = configOptions.sslHandshakeTimeout();
+ if (configOptions.trustSelfSignedCertificates()) {
+ httpClient = httpClient.secure(sslSpecification -> {
+ SslProvider.Builder sslBuilder = sslSpecification.sslContext(buildTrustAllSslContext());
+ if (handshakeTimeout.isPresent()) {
+ sslBuilder.handshakeTimeout(handshakeTimeout.get());
+ }
+ });
+ } else if (handshakeTimeout.isPresent()) {
+ httpClient = httpClient.secure(sslSpecification -> {
+ SslProvider.Builder sslBuilder = sslSpecification.sslContext(buildDefaultClientSslContext());
+ sslBuilder.handshakeTimeout(handshakeTimeout.get());
+ });
+ } else {
+ httpClient = httpClient.secure();
+ }
+
+ return httpClient;
+ }
+
+ private static SslContext buildDefaultClientSslContext() {
+ try {
+ return SslContextBuilder.forClient()
+ .build();
+ } catch (SSLException e) {
+ throw new IllegalStateException(Messages.ERROR_OCCURRED_SETTING_UP_DEFAULT_SSL_CONTEXT, e);
+ }
+ }
+
+ private static SslContext buildTrustAllSslContext() {
+ try {
+ return SslContextBuilder.forClient()
+ .trustManager(getTrustAllCertificatesManager())
+ .build();
+ } catch (SSLException e) {
+ throw new IllegalStateException(Messages.ERROR_OCCURRED_SETTING_UP_ALWAYS_APPROVING_SSL_CONTEXT, e);
+ }
+ }
+
+ private static X509TrustManager getTrustAllCertificatesManager() {
+ return new X509TrustManager() {
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[] {};
+ }
+
+ };
+ }
+
+}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientFactory.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientFactory.java
index d2258ed03c..32c8c45c33 100644
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientFactory.java
+++ b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientFactory.java
@@ -1,24 +1,39 @@
package org.cloudfoundry.multiapps.controller.client.facade.rest;
-import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.CloudFoundryClientFactory;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableCloudFoundryClientFactory;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudSpace;
-import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuthClient;
-import org.cloudfoundry.multiapps.controller.client.facade.util.RestUtil;
-import org.cloudfoundry.client.CloudFoundryClient;
-import org.immutables.value.Value;
-
+import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URL;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.text.MessageFormat;
import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+
+import org.cloudfoundry.multiapps.controller.Constants;
+import org.cloudfoundry.multiapps.controller.Messages;
+import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials;
+import org.cloudfoundry.multiapps.controller.client.facade.CloudException;
+import org.cloudfoundry.multiapps.controller.client.facade.adapters.LogCacheClient;
+import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudSpace;
+import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuthClient;
+import org.cloudfoundry.multiapps.controller.client.facade.util.JsonUtil;
+import org.cloudfoundry.multiapps.controller.client.facade.util.RestUtil;
+import org.immutables.value.Value;
+import org.springframework.web.client.RestClient;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.netty.http.client.HttpClient;
@Value.Immutable
public abstract class CloudControllerRestClientFactory {
+
private final RestUtil restUtil = new RestUtil();
+ private final Map cachedHttpConnectionPair = new ConcurrentHashMap<>();
+
public abstract Optional getSslHandshakeTimeout();
public abstract Optional getConnectTimeout();
@@ -34,38 +49,165 @@ public boolean shouldTrustSelfSignedCertificates() {
return false;
}
- @Value.Derived
- public CloudFoundryClientFactory getCloudFoundryClientFactory() {
- ImmutableCloudFoundryClientFactory.Builder builder = ImmutableCloudFoundryClientFactory.builder();
- getSslHandshakeTimeout().ifPresent(builder::sslHandshakeTimeout);
- getConnectTimeout().ifPresent(builder::connectTimeout);
- getConnectionPoolSize().ifPresent(builder::connectionPoolSize);
- getThreadPoolSize().ifPresent(builder::threadPoolSize);
- getResponseTimeout().ifPresent(builder::responseTimeout);
- return builder.build();
- }
-
public CloudControllerRestClient createClient(URL controllerUrl, CloudCredentials credentials, String organizationName,
String spaceName, OAuthClient oAuthClient, Map requestTags) {
oAuthClient.init(credentials);
- CloudSpaceClient spaceGetter = getCloudFoundryClientFactory().createSpaceClient(controllerUrl, oAuthClient, requestTags);
- CloudSpace target = spaceGetter.getSpace(organizationName, spaceName);
+ CloudSpace target = createSpaceClient(controllerUrl, oAuthClient, requestTags).getSpace(organizationName, spaceName);
return createClient(controllerUrl, credentials, target, oAuthClient, requestTags);
}
public CloudControllerRestClient createClient(URL controllerUrl, CloudCredentials credentials, CloudSpace target) {
- return createClient(controllerUrl, credentials, target, createOAuthClient(controllerUrl, credentials.getOrigin()),
+ return createClient(controllerUrl, credentials, target, createOAuthClient(controllerUrl),
Collections.emptyMap());
}
public CloudControllerRestClient createClient(URL controllerUrl, CloudCredentials credentials, CloudSpace target,
OAuthClient oAuthClient, Map requestTags) {
oAuthClient.init(credentials);
- CloudFoundryClient delegate = getCloudFoundryClientFactory().createClient(controllerUrl, oAuthClient, requestTags);
- return new CloudControllerRestClientImpl(delegate, target);
+ HttpConnectionPair httpConnectionPair = getCachedHttpConnectionPair(controllerUrl, requestTags);
+ URL v3ApiUrl = httpConnectionPair.v3ApiUrl();
+ URL baseUrl = extractBaseUrl(v3ApiUrl);
+
+ HttpClient httpClient = httpConnectionPair.httpClient();
+ RestClient restClient = CloudControllerRestClientBuilder.buildRestClient(httpClient, baseUrl, oAuthClient, requestTags);
+ WebClient webClient = CloudControllerRestClientBuilder.buildWebClient(httpClient, baseUrl, oAuthClient, requestTags);
+
+ CloudControllerV3Client client = new CloudControllerV3Client(restClient, webClient);
+
+ Function uploadRestClientFactory = uploadTimeout -> {
+ ClientConfigurationOptions uploadOptions = new ClientConfigurationOptions(getConnectTimeout(), Optional.of(uploadTimeout),
+ getSslHandshakeTimeout(), getConnectionPoolSize(),
+ Optional.empty(),
+ shouldTrustSelfSignedCertificates());
+ return CloudControllerRestClientBuilder.build(baseUrl, oAuthClient, requestTags, uploadOptions);
+ };
+
+ return new CloudControllerRestClientV3Impl(target, client, uploadRestClientFactory);
+ }
+
+ public CloudSpaceClient createSpaceClient(URL controllerUrl, OAuthClient oAuthClient, Map requestTags) {
+ HttpConnectionPair httpConnectionPair = getCachedHttpConnectionPair(controllerUrl, requestTags);
+ URL baseUrl = extractBaseUrl(httpConnectionPair.v3ApiUrl());
+
+ RestClient restClient = CloudControllerRestClientBuilder.buildRestClient(httpConnectionPair.httpClient(), baseUrl, oAuthClient,
+ requestTags);
+ WebClient webClient = CloudControllerRestClientBuilder.buildWebClient(httpConnectionPair.httpClient(), baseUrl, oAuthClient,
+ requestTags);
+
+ return new CloudSpaceClient(new CloudControllerV3Client(restClient, webClient));
+ }
+
+ public LogCacheClient createLogCacheClient(URL controllerUrl, OAuthClient oAuthClient, Map requestTags) {
+ HttpConnectionPair httpConnectionPair = getCachedHttpConnectionPair(controllerUrl, requestTags);
+ RestClient restClient = CloudControllerRestClientBuilder.buildRestClient(httpConnectionPair.httpClient(),
+ httpConnectionPair.logCacheUrl(),
+ oAuthClient, requestTags);
+ return new LogCacheClient(restClient);
+ }
+
+ private HttpConnectionPair getCachedHttpConnectionPair(URL controllerUrl, Map requestTags) {
+ return cachedHttpConnectionPair.computeIfAbsent(controllerUrl.getHost(), host -> {
+ HttpClient httpClient = CloudControllerRestClientBuilder.buildHttpClient(getClientConfigurationOptions());
+ URL v3ApiUrl = resolveV3ApiUrl(controllerUrl, requestTags);
+ URL logCacheUrl = resolveLogCacheUrl(controllerUrl, requestTags);
+ return new HttpConnectionPair(httpClient, v3ApiUrl, logCacheUrl);
+ });
+ }
+
+ private ClientConfigurationOptions getClientConfigurationOptions() {
+ return new ClientConfigurationOptions(getConnectTimeout(), getResponseTimeout(), getSslHandshakeTimeout(),
+ getConnectionPoolSize(), getThreadPoolSize(),
+ shouldTrustSelfSignedCertificates());
+ }
+
+ private URL extractBaseUrl(URL url) {
+ try {
+ int port = url.getPort();
+ String origin = url.getProtocol() + Constants.PROTOCOL_SEPARATOR + url.getHost() + (port == Constants.UNDEFINED_PORT
+ ? Constants.EMPTY_STRING
+ : Constants.COLON + port);
+ return URI.create(origin)
+ .toURL();
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException(MessageFormat.format(Messages.COULD_NOT_DETERMINE_API_ORIGIN_FROM_0, url), e);
+ }
+ }
+
+ private URL resolveV3ApiUrl(URL controllerUrl, Map requestTags) {
+ try {
+ Map rootDocumentLinks = getCloudControllerRootDocumentLinks(controllerUrl, requestTags);
+ Map cloudControllerUrlV3 = (Map) rootDocumentLinks.get(
+ Constants.CLOUD_CONTROLLER_CF_ROOT_DOCUMENT_NAME);
+ return URI.create((String) cloudControllerUrlV3.get(Constants.HREF))
+ .toURL();
+ } catch (Exception e) {
+ return fallbackUrl(controllerUrl, Constants.CF_API_V3);
+ }
+ }
+
+ private URL resolveLogCacheUrl(URL controllerUrl, Map requestTags) {
+ try {
+ Map rootDocumentLinks = getCloudControllerRootDocumentLinks(controllerUrl, requestTags);
+ Map logCacheUrl = (Map) rootDocumentLinks.get(Constants.LOG_CACHE_CF_ROOT_DOCUMENT_NAME);
+ return URI.create((String) logCacheUrl.get(Constants.HREF))
+ .toURL();
+ } catch (Exception e) {
+ String host = controllerUrl.getHost();
+ String logCacheHost = host.startsWith(Constants.API_HOST_PREFIX) ? Constants.LOG_CACHE_PREFIX + host.substring(
+ Constants.API_HOST_PREFIX.length()) : Constants.LOG_CACHE_PREFIX + host;
+ try {
+ return URI.create(controllerUrl.getProtocol() + Constants.PROTOCOL_SEPARATOR + logCacheHost)
+ .toURL();
+ } catch (MalformedURLException me) {
+ throw new CloudException(MessageFormat.format(Messages.COULD_NOT_RESOLVE_LOG_CACHE_URL_FROM_0, controllerUrl), me);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map getCloudControllerRootDocumentLinks(URL controllerUrl, Map requestTags) {
+ try {
+ HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
+ .GET()
+ .uri(controllerUrl.toURI())
+ .timeout(Constants.DEFAULT_CONNECT_TIMEOUT);
+ requestTags.forEach(requestBuilder::header);
+ HttpResponse response = getSimpleHttpClient().send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() / 100 != 2) {
+ throw new CloudException(
+ MessageFormat.format(Messages.CF_ROOT_DOCUMENT_REQUEST_TO_0_RETURNED_1, controllerUrl, response.statusCode()));
+ }
+
+ return (Map) JsonUtil.convertJsonToMap(response.body())
+ .get(Constants.ROOT_DOCUMENT_LINKS_LIST);
+ } catch (InterruptedException e) {
+ Thread.currentThread()
+ .interrupt();
+ throw new CloudException(MessageFormat.format(Messages.INTERRUPTED_WHILE_CALLING_THE_CF_ROOT_URL_AT_0, controllerUrl), e);
+ } catch (Exception e) {
+ throw new CloudException(MessageFormat.format(Messages.FAILED_TO_CALL_THE_CF_ROOT_AT_0_WITH_1, controllerUrl, e.getMessage()),
+ e);
+ }
+ }
+
+ private static java.net.http.HttpClient getSimpleHttpClient() {
+ return java.net.http.HttpClient.newBuilder()
+ .connectTimeout(Constants.DEFAULT_CONNECT_TIMEOUT)
+ .build();
+ }
+
+ private URL fallbackUrl(URL controllerUrl, String pathSuffix) {
+ try {
+ return URI.create(controllerUrl.toString() + pathSuffix)
+ .toURL();
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException(
+ MessageFormat.format(Messages.COULD_NOT_RESOLVE_URL_FROM_0_1, controllerUrl, pathSuffix), e);
+ }
}
- private OAuthClient createOAuthClient(URL controllerUrl, String origin) {
+ private OAuthClient createOAuthClient(URL controllerUrl) {
return restUtil.createOAuthClientByControllerUrl(controllerUrl, shouldTrustSelfSignedCertificates());
}
diff --git a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientImpl.java b/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientImpl.java
deleted file mode 100644
index c1e6718d16..0000000000
--- a/multiapps-controller-client/src/main/java/org/cloudfoundry/multiapps/controller/client/facade/rest/CloudControllerRestClientImpl.java
+++ /dev/null
@@ -1,2621 +0,0 @@
-package org.cloudfoundry.multiapps.controller.client.facade.rest;
-
-import java.nio.file.Path;
-import java.text.MessageFormat;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.function.IntFunction;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import org.cloudfoundry.AbstractCloudFoundryException;
-import org.cloudfoundry.client.CloudFoundryClient;
-import org.cloudfoundry.client.v3.BuildpackData;
-import org.cloudfoundry.client.v3.DockerData;
-import org.cloudfoundry.client.v3.Lifecycle;
-import org.cloudfoundry.client.v3.LifecycleType;
-import org.cloudfoundry.client.v3.Metadata;
-import org.cloudfoundry.client.v3.Relationship;
-import org.cloudfoundry.client.v3.Resource;
-import org.cloudfoundry.client.v3.ToOneRelationship;
-import org.cloudfoundry.client.v3.applications.Application;
-import org.cloudfoundry.client.v3.applications.ApplicationFeature;
-import org.cloudfoundry.client.v3.applications.ApplicationRelationships;
-import org.cloudfoundry.client.v3.applications.ApplicationState;
-import org.cloudfoundry.client.v3.applications.CreateApplicationRequest;
-import org.cloudfoundry.client.v3.applications.CreateApplicationResponse;
-import org.cloudfoundry.client.v3.applications.DeleteApplicationRequest;
-import org.cloudfoundry.client.v3.applications.GetApplicationCurrentDropletRequest;
-import org.cloudfoundry.client.v3.applications.GetApplicationCurrentDropletResponse;
-import org.cloudfoundry.client.v3.applications.GetApplicationEnvironmentVariablesRequest;
-import org.cloudfoundry.client.v3.applications.GetApplicationEnvironmentVariablesResponse;
-import org.cloudfoundry.client.v3.applications.GetApplicationProcessRequest;
-import org.cloudfoundry.client.v3.applications.GetApplicationProcessResponse;
-import org.cloudfoundry.client.v3.applications.GetApplicationProcessStatisticsRequest;
-import org.cloudfoundry.client.v3.applications.GetApplicationProcessStatisticsResponse;
-import org.cloudfoundry.client.v3.applications.GetApplicationRequest;
-import org.cloudfoundry.client.v3.applications.GetApplicationSshEnabledRequest;
-import org.cloudfoundry.client.v3.applications.GetApplicationSshEnabledResponse;
-import org.cloudfoundry.client.v3.applications.ListApplicationBuildsRequest;
-import org.cloudfoundry.client.v3.applications.ListApplicationFeaturesRequest;
-import org.cloudfoundry.client.v3.applications.ListApplicationPackagesRequest;
-import org.cloudfoundry.client.v3.applications.ListApplicationRoutesRequest;
-import org.cloudfoundry.client.v3.applications.ListApplicationsRequest;
-import org.cloudfoundry.client.v3.applications.ScaleApplicationRequest;
-import org.cloudfoundry.client.v3.applications.SetApplicationCurrentDropletRequest;
-import org.cloudfoundry.client.v3.applications.StartApplicationRequest;
-import org.cloudfoundry.client.v3.applications.StopApplicationRequest;
-import org.cloudfoundry.client.v3.applications.UpdateApplicationEnvironmentVariablesRequest;
-import org.cloudfoundry.client.v3.applications.UpdateApplicationFeatureRequest;
-import org.cloudfoundry.client.v3.applications.UpdateApplicationRequest;
-import org.cloudfoundry.client.v3.applications.UpdateApplicationResponse;
-import org.cloudfoundry.client.v3.auditevents.AuditEventResource;
-import org.cloudfoundry.client.v3.auditevents.ListAuditEventsRequest;
-import org.cloudfoundry.client.v3.builds.Build;
-import org.cloudfoundry.client.v3.builds.CreateBuildRequest;
-import org.cloudfoundry.client.v3.builds.GetBuildRequest;
-import org.cloudfoundry.client.v3.builds.ListBuildsRequest;
-import org.cloudfoundry.client.v3.domains.CreateDomainRequest;
-import org.cloudfoundry.client.v3.domains.DeleteDomainRequest;
-import org.cloudfoundry.client.v3.domains.Domain;
-import org.cloudfoundry.client.v3.domains.DomainRelationships;
-import org.cloudfoundry.client.v3.domains.DomainResource;
-import org.cloudfoundry.client.v3.domains.ListDomainsRequest;
-import org.cloudfoundry.client.v3.jobs.GetJobRequest;
-import org.cloudfoundry.client.v3.organizations.GetOrganizationDefaultDomainRequest;
-import org.cloudfoundry.client.v3.organizations.ListOrganizationDomainsRequest;
-import org.cloudfoundry.client.v3.packages.CreatePackageRequest;
-import org.cloudfoundry.client.v3.packages.CreatePackageResponse;
-import org.cloudfoundry.client.v3.packages.GetPackageRequest;
-import org.cloudfoundry.client.v3.packages.Package;
-import org.cloudfoundry.client.v3.packages.PackageRelationships;
-import org.cloudfoundry.client.v3.packages.PackageResource;
-import org.cloudfoundry.client.v3.packages.PackageType;
-import org.cloudfoundry.client.v3.packages.UploadPackageRequest;
-import org.cloudfoundry.client.v3.processes.Data;
-import org.cloudfoundry.client.v3.processes.HealthCheck;
-import org.cloudfoundry.client.v3.processes.HealthCheckType;
-import org.cloudfoundry.client.v3.processes.ReadinessHealthCheck;
-import org.cloudfoundry.client.v3.processes.ReadinessHealthCheckType;
-import org.cloudfoundry.client.v3.processes.UpdateProcessRequest;
-import org.cloudfoundry.client.v3.roles.ListRolesRequest;
-import org.cloudfoundry.client.v3.roles.RoleResource;
-import org.cloudfoundry.client.v3.roles.RoleType;
-import org.cloudfoundry.client.v3.routes.CreateRouteRequest;
-import org.cloudfoundry.client.v3.routes.CreateRouteResponse;
-import org.cloudfoundry.client.v3.routes.DeleteRouteRequest;
-import org.cloudfoundry.client.v3.routes.Destination;
-import org.cloudfoundry.client.v3.routes.InsertRouteDestinationsRequest;
-import org.cloudfoundry.client.v3.routes.ListRoutesRequest;
-import org.cloudfoundry.client.v3.routes.RemoveRouteDestinationsRequest;
-import org.cloudfoundry.client.v3.routes.RouteRelationships;
-import org.cloudfoundry.client.v3.routes.RouteResource;
-import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingRequest;
-import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingResponse;
-import org.cloudfoundry.client.v3.servicebindings.DeleteServiceBindingRequest;
-import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingDetailsRequest;
-import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingDetailsResponse;
-import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingParametersRequest;
-import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingParametersResponse;
-import org.cloudfoundry.client.v3.servicebindings.ListServiceBindingsRequest;
-import org.cloudfoundry.client.v3.servicebindings.ServiceBindingRelationships;
-import org.cloudfoundry.client.v3.servicebindings.ServiceBindingResource;
-import org.cloudfoundry.client.v3.servicebindings.ServiceBindingType;
-import org.cloudfoundry.client.v3.servicebindings.UpdateServiceBindingRequest;
-import org.cloudfoundry.client.v3.servicebrokers.BasicAuthentication;
-import org.cloudfoundry.client.v3.servicebrokers.CreateServiceBrokerRequest;
-import org.cloudfoundry.client.v3.servicebrokers.DeleteServiceBrokerRequest;
-import org.cloudfoundry.client.v3.servicebrokers.ListServiceBrokersRequest;
-import org.cloudfoundry.client.v3.servicebrokers.ServiceBrokerRelationships;
-import org.cloudfoundry.client.v3.servicebrokers.ServiceBrokerResource;
-import org.cloudfoundry.client.v3.servicebrokers.UpdateServiceBrokerRequest;
-import org.cloudfoundry.client.v3.serviceinstances.CreateServiceInstanceRequest;
-import org.cloudfoundry.client.v3.serviceinstances.DeleteServiceInstanceRequest;
-import org.cloudfoundry.client.v3.serviceinstances.GetManagedServiceParametersRequest;
-import org.cloudfoundry.client.v3.serviceinstances.GetManagedServiceParametersResponse;
-import org.cloudfoundry.client.v3.serviceinstances.GetServiceInstanceRequest;
-import org.cloudfoundry.client.v3.serviceinstances.GetUserProvidedCredentialsRequest;
-import org.cloudfoundry.client.v3.serviceinstances.GetUserProvidedCredentialsResponse;
-import org.cloudfoundry.client.v3.serviceinstances.ListServiceInstancesRequest;
-import org.cloudfoundry.client.v3.serviceinstances.ServiceInstance;
-import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceRelationships;
-import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceResource;
-import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceType;
-import org.cloudfoundry.client.v3.serviceinstances.UpdateServiceInstanceRequest;
-import org.cloudfoundry.client.v3.serviceofferings.GetServiceOfferingRequest;
-import org.cloudfoundry.client.v3.serviceofferings.ListServiceOfferingsRequest;
-import org.cloudfoundry.client.v3.serviceofferings.ServiceOffering;
-import org.cloudfoundry.client.v3.serviceofferings.ServiceOfferingResource;
-import org.cloudfoundry.client.v3.serviceplans.GetServicePlanRequest;
-import org.cloudfoundry.client.v3.serviceplans.ListServicePlansRequest;
-import org.cloudfoundry.client.v3.serviceplans.ServicePlan;
-import org.cloudfoundry.client.v3.serviceplans.ServicePlanResource;
-import org.cloudfoundry.client.v3.serviceplans.UpdateServicePlanVisibilityRequest;
-import org.cloudfoundry.client.v3.serviceplans.Visibility;
-import org.cloudfoundry.client.v3.spaces.DeleteUnmappedRoutesRequest;
-import org.cloudfoundry.client.v3.stacks.ListStacksRequest;
-import org.cloudfoundry.client.v3.stacks.Stack;
-import org.cloudfoundry.client.v3.tasks.CancelTaskRequest;
-import org.cloudfoundry.client.v3.tasks.CreateTaskRequest;
-import org.cloudfoundry.client.v3.tasks.GetTaskRequest;
-import org.cloudfoundry.client.v3.tasks.ListTasksRequest;
-import org.cloudfoundry.client.v3.tasks.Task;
-import org.cloudfoundry.multiapps.controller.client.facade.CloudOperationException;
-import org.cloudfoundry.multiapps.controller.client.facade.Constants;
-import org.cloudfoundry.multiapps.controller.client.facade.Messages;
-import org.cloudfoundry.multiapps.controller.client.facade.UploadStatusCallback;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudApplication;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudAsyncJob;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudBuild;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudDomain;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudEvent;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudPackage;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudProcess;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudRoute;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudServiceBinding;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudServiceBroker;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudServiceInstance;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudServiceKey;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudServiceOffering;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudServicePlan;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudStack;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawCloudTask;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawInstancesInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawUserRole;
-import org.cloudfoundry.multiapps.controller.client.facade.adapters.ImmutableRawV3CloudServiceInstance;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.BitsData;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudApplication;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudAsyncJob;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudBuild;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudDomain;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudEntity;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudEvent;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudMetadata;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudPackage;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudProcess;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudRoute;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceBinding;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceBroker;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceInstance;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceKey;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceOffering;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServicePlan;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudSpace;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudStack;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudTask;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Derivable;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.DockerCredentials;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.DockerInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.DropletInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ErrorDetails;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableDropletInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableErrorDetails;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableInstancesInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableUpload;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.InstancesInfo;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.RouteDestination;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.ServicePlanVisibility;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Staging;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Status;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.Upload;
-import org.cloudfoundry.multiapps.controller.client.facade.domain.UserRole;
-import org.cloudfoundry.multiapps.controller.client.facade.dto.ApplicationToCreateDto;
-import org.cloudfoundry.multiapps.controller.client.facade.util.JobV3Util;
-import org.cloudfoundry.util.PaginationUtils;
-import org.springframework.http.HttpStatus;
-import org.springframework.util.Assert;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-/**
- * Abstract implementation of the CloudControllerClient intended to serve as the base.
- */
-public class CloudControllerRestClientImpl implements CloudControllerRestClient {
-
- private static final long PACKAGE_UPLOAD_JOB_POLLING_PERIOD = TimeUnit.SECONDS.toMillis(5);
- private static final Duration DELETE_JOB_TIMEOUT = Duration.ofMinutes(5);
- private static final Duration BINDING_OPERATIONS_TIMEOUT = Duration.ofMinutes(10);
- private static final int MAX_CHAR_LENGTH_FOR_PARAMS_IN_REQUEST = 4000;
-
- private CloudSpace target; // optional, as some operations do not require a targeted space
- private CloudFoundryClient delegate;
-
- /**
- * Only for unit tests. This works around the fact that the initialize method is called within the constructor and hence can not be
- * overloaded, making it impossible to write unit tests that don't trigger network calls.
- */
- protected CloudControllerRestClientImpl() {
- }
-
- public CloudControllerRestClientImpl(CloudFoundryClient delegate) {
- this(delegate, null);
- }
-
- public CloudControllerRestClientImpl(CloudFoundryClient delegate, CloudSpace target) {
- this.target = target;
- this.delegate = delegate;
- }
-
- @Override
- public CloudSpace getTarget() {
- return target;
- }
-
- @Override
- public void addDomain(String domainName) {
- assertSpaceProvided("add domain");
- CloudDomain domain = findDomainByName(domainName);
- if (domain == null) {
- doCreateDomain(domainName);
- }
- }
-
- @Override
- public void addRoute(String host, String domainName, String path) {
- assertSpaceProvided("add route for domain");
- UUID domainGuid = getRequiredDomainGuid(domainName);
- doAddRoute(domainGuid, host, path);
- }
-
- @Override
- public Optional bindServiceInstance(String bindingName, String applicationName, String serviceInstanceName) {
- return bindServiceInstance(bindingName, applicationName, serviceInstanceName, null);
- }
-
- @Override
- public Optional bindServiceInstance(String bindingName, String applicationName, String serviceInstanceName,
- Map parameters) {
- UUID applicationGuid = getRequiredApplicationGuid(applicationName);
- UUID serviceInstanceGuid = getRequiredServiceInstanceGuid(serviceInstanceName);
-
- var createBindingRequest = CreateServiceBindingRequest.builder()
- .name(bindingName)
- .type(ServiceBindingType.APPLICATION)
- .relationships(ServiceBindingRelationships.builder()
- .application(buildToOneRelationship(
- applicationGuid))
- .serviceInstance(
- buildToOneRelationship(
- serviceInstanceGuid))
- .build());
- if (!CollectionUtils.isEmpty(parameters)) {
- createBindingRequest.parameters(parameters);
- }
- return delegate.serviceBindingsV3()
- .create(createBindingRequest.build())
- .map(CreateServiceBindingResponse::getJobId)
- .block();
- }
-
- @Override
- public void createApplication(ApplicationToCreateDto applicationToCreateDto) {
- assertSpaceProvided("create application");
- CreateApplicationRequest createApplicationRequest = CreateApplicationRequest.builder()
- .name(applicationToCreateDto.getName())
- .metadata(applicationToCreateDto.getMetadata())
- .lifecycle(buildApplicationLifecycle(
- applicationToCreateDto.getStaging()))
- .relationships(buildApplicationRelationships())
- .environmentVariables(applicationToCreateDto.getEnv())
- .build();
- CreateApplicationResponse createApplicationResponse = delegate.applicationsV3()
- .create(createApplicationRequest)
- .block();
- updateApplicationAttributes(applicationToCreateDto, createApplicationResponse.getId());
- }
-
- private Lifecycle buildApplicationLifecycle(Staging staging) {
- // Prioritize Docker lifecycle if DockerInfo is provided
- if (staging.getDockerInfo() != null) {
- return createDockerLifecycle();
- }
-
- // Determine lifecycle type, defaulting to BUILDPACK if lifecycleType is null
- LifecycleType lifecycleType = staging.getLifecycleType() != null ? LifecycleType.valueOf(staging.getLifecycleType()
- .name()) : LifecycleType.BUILDPACK;
-
- return createLifecycleByType(staging, lifecycleType);
- }
-
- private Lifecycle createLifecycleByType(Staging staging, LifecycleType lifecycleType) {
- validateLifecycleConfiguration(staging, lifecycleType);
- BuildpackData buildpackData = createBuildpackData(staging);
- return Lifecycle.builder()
- .type(lifecycleType)
- .data(buildpackData)
- .build();
- }
-
- private Lifecycle createDockerLifecycle() {
- return Lifecycle.builder()
- .type(LifecycleType.DOCKER)
- .data(DockerData.builder()
- .build())
- .build();
- }
-
- private void validateLifecycleConfiguration(Staging staging, LifecycleType lifecycleType) {
- if (lifecycleType == LifecycleType.CNB && CollectionUtils.isEmpty(staging.getBuildpacks())) {
- throw new IllegalArgumentException(Messages.BUILDPACKS_ARE_REQUIRED_FOR_CNB_LIFECYCLE_TYPE);
- }
- }
-
- private BuildpackData createBuildpackData(Staging staging) {
- BuildpackData.Builder buildpackDataBuilder = BuildpackData.builder()
- .stack(staging.getStackName());
- if (staging.getBuildpacks() != null) {
- buildpackDataBuilder.addAllBuildpacks(staging.getBuildpacks());
- }
- return buildpackDataBuilder.build();
- }
-
- private ApplicationRelationships buildApplicationRelationships() {
- return ApplicationRelationships.builder()
- .space(buildToOneRelationship(getTargetSpaceGuid()))
- .build();
- }
-
- private void updateApplicationAttributes(ApplicationToCreateDto applicationToCreateDto, String applicationGuid) {
- UUID createdApplicationGuid = UUID.fromString(applicationGuid);
- updateApplicationProcess(createdApplicationGuid, applicationToCreateDto.getStaging());
- delegate.applicationsV3()
- .scale(ScaleApplicationRequest.builder()
- .applicationId(createdApplicationGuid.toString())
- .type("web")
- .memoryInMb(applicationToCreateDto.getMemoryInMb())
- .diskInMb(applicationToCreateDto.getDiskQuotaInMb())
- .build())
- .block();
- if (!CollectionUtils.isEmpty(applicationToCreateDto.getRoutes())) {
- addRoutes(applicationToCreateDto.getRoutes(), createdApplicationGuid);
- }
- }
-
- private void updateApplicationProcess(UUID applicationGuid, Staging staging) {
- staging.getAppFeatures()
- .entrySet()
- .forEach(entry -> updateAppFeature(applicationGuid, entry.getKey(), entry.getValue()));
- GetApplicationProcessResponse getApplicationProcessResponse = getApplicationProcessResource(applicationGuid);
- UpdateProcessRequest.Builder updateProcessRequestBuilder = UpdateProcessRequest.builder()
- .processId(getApplicationProcessResponse.getId())
- .command(staging.getCommand());
- if (staging.getHealthCheckType() != null) {
- updateProcessRequestBuilder.healthCheck(buildHealthCheck(staging));
- }
- if (staging.getReadinessHealthCheckType() != null) {
- updateProcessRequestBuilder.readinessHealthCheck(buildReadinessHealthCheck(staging));
- }
- delegate.processes()
- .update(updateProcessRequestBuilder.build())
- .block();
- }
-
- private ReadinessHealthCheck buildReadinessHealthCheck(Staging staging) {
- return ReadinessHealthCheck.builder()
- .type(ReadinessHealthCheckType.from(staging.getReadinessHealthCheckType()))
- .data(buildReadinessHealthCheckData(staging))
- .build();
- }
-
- private Data buildReadinessHealthCheckData(Staging staging) {
- return Data.builder()
- .invocationTimeout(staging.getReadinessHealthCheckInvocationTimeout())
- .endpoint(staging.getReadinessHealthCheckHttpEndpoint())
- .interval(staging.getReadinessHealthCheckInterval())
- .build();
- }
-
- private void updateAppFeature(UUID applicationGuid, String featureName, boolean enabled) {
- delegate.applicationsV3()
- .updateFeature(UpdateApplicationFeatureRequest.builder()
- .featureName(featureName)
- .enabled(enabled)
- .applicationId(applicationGuid.toString())
- .build())
- .block();
- }
-
- private GetApplicationProcessResponse getApplicationProcessResource(UUID applicationGuid) {
- return delegate.applicationsV3()
- .getProcess(GetApplicationProcessRequest.builder()
- .type("web")
- .applicationId(applicationGuid.toString())
- .build())
- .block();
- }
-
- private HealthCheck buildHealthCheck(Staging staging) {
- HealthCheckType healthCheckType = HealthCheckType.from(staging.getHealthCheckType());
- return HealthCheck.builder()
- .type(healthCheckType)
- .data(Data.builder()
- .endpoint(staging.getHealthCheckHttpEndpoint())
- .timeout(staging.getHealthCheckTimeout())
- .invocationTimeout(staging.getInvocationTimeout())
- .interval(staging.getHealthCheckInterval())
- .build())
- .build();
- }
-
- private void addRoutes(Set routes, UUID applicationGuid) {
- Map domains = getDomainsFromRoutes(routes);
- for (CloudRoute route : routes) {
- validateDomainForRoute(route, domains);
- UUID domainGuid = domains.get(route.getDomain()
- .getName());
- UUID routeGuid = getOrAddRoute(domainGuid, route.getHost(), route.getPath());
- bindRoute(routeGuid, applicationGuid, route.getRequestedProtocol());
- }
- }
-
- @Override
- public void createServiceInstance(CloudServiceInstance serviceInstance) {
- assertSpaceProvided("create service instance");
- Assert.notNull(serviceInstance, "Service instance must not be null.");
- CloudServicePlan servicePlan = findPlanForService(serviceInstance, serviceInstance.getPlan());
- UUID servicePlanGuid = servicePlan.getGuid();
-
- delegate.serviceInstancesV3()
- .create(CreateServiceInstanceRequest.builder()
- .type(ServiceInstanceType.MANAGED)
- .name(serviceInstance.getName())
- .metadata(serviceInstance.getV3Metadata())
- .relationships(ServiceInstanceRelationships.builder()
- .servicePlan(buildToOneRelationship(
- servicePlanGuid.toString()))
- .space(buildToOneRelationship(
- getTargetSpaceGuid().toString()))
- .build())
- .tags(serviceInstance.getTags())
- .parameters(serviceInstance.getCredentials())
- .build())
- .block();
- }
-
- @Override
- public String createServiceBroker(CloudServiceBroker serviceBroker) {
- Assert.notNull(serviceBroker, "Service broker must not be null.");
-
- ServiceBrokerRelationships serviceBrokerRelationship = Optional.ofNullable(serviceBroker.getSpaceGuid())
- .map(UUID::fromString)
- .map(this::buildToOneRelationship)
- .map(spaceRelationship -> ServiceBrokerRelationships.builder()
- .space(
- spaceRelationship)
- .build())
- .orElse(null);
-
- return delegate.serviceBrokersV3()
- .create(CreateServiceBrokerRequest.builder()
- .name(serviceBroker.getName())
- .url(serviceBroker.getUrl())
- .authentication(BasicAuthentication.builder()
- .username(serviceBroker.getUsername())
- .password(serviceBroker.getPassword())
- .build())
- .relationships(serviceBrokerRelationship)
- .build())
- .block();
- }
-
- @Override
- public CloudServiceKey createAndFetchServiceKey(CloudServiceKey keyModel, String serviceInstanceName) {
- CloudServiceInstance serviceInstance = getServiceInstance(serviceInstanceName);
- doCreateServiceKeySync(keyModel.getName(), keyModel.getCredentials(), keyModel.getV3Metadata(), serviceInstance);
-
- return fetchWithAuxiliaryContent(
- () -> getServiceKeyResourceByNameAndServiceInstanceGuid(keyModel.getName(), getGuid(serviceInstance)),
- fetchedKey -> zipWithAuxiliaryServiceKeyContent(fetchedKey, serviceInstance));
- }
-
- @Override
- public Optional createServiceKey(CloudServiceKey keyModel, String serviceInstanceName) {
- CloudServiceInstance serviceInstance = getServiceInstance(serviceInstanceName);
- return doCreateServiceKey(keyModel.getName(), keyModel.getCredentials(), keyModel.getV3Metadata(), serviceInstance);
- }
-
- @Override
- public Optional createServiceKey(String serviceInstanceName, String serviceKeyName, Map parameters) {
- CloudServiceInstance serviceInstance = getServiceInstance(serviceInstanceName);
- return doCreateServiceKey(serviceKeyName, parameters, null, serviceInstance);
- }
-
- private void doCreateServiceKeySync(String name, Map parameters, Metadata metadata,
- CloudServiceInstance serviceInstance) {
- CreateServiceBindingRequest createServiceBindingRequest = buildServiceCredentialBindingRequest(name, parameters, metadata,
- serviceInstance);
- delegate.serviceBindingsV3()
- .create(createServiceBindingRequest)
- .map(response -> response.getJobId()
- .get())
- .flatMap(jobId -> JobV3Util.waitForCompletion(delegate, BINDING_OPERATIONS_TIMEOUT, jobId))
- .block();
- }
-
- private Optional doCreateServiceKey(String name, Map parameters, Metadata metadata,
- CloudServiceInstance serviceInstance) {
- CreateServiceBindingRequest createServiceBindingRequest = buildServiceCredentialBindingRequest(name, parameters, metadata,
- serviceInstance);
- return delegate.serviceBindingsV3()
- .create(createServiceBindingRequest)
- .map(CreateServiceBindingResponse::getJobId)
- .block();
- }
-
- private CreateServiceBindingRequest buildServiceCredentialBindingRequest(String name, Map parameters, Metadata metadata,
- CloudServiceInstance serviceInstance) {
- if (serviceInstance.getType() != ServiceInstanceType.MANAGED) {
- throw new IllegalArgumentException(
- String.format(Messages.CANT_CREATE_SERVICE_KEY_FOR_USER_PROVIDED_SERVICE, serviceInstance.getName()));
- }
- UUID serviceInstanceGuid = getGuid(serviceInstance);
-
- var createBindingRequest = CreateServiceBindingRequest.builder()
- .type(ServiceBindingType.KEY)
- .name(name)
- .metadata(metadata)
- .relationships(ServiceBindingRelationships.builder()
- .serviceInstance(
- buildToOneRelationship(
- serviceInstanceGuid))
- .build());
- if (!CollectionUtils.isEmpty(parameters)) {
- createBindingRequest.parameters(parameters);
- }
- return createBindingRequest.build();
- }
-
- @Override
- public void createUserProvidedServiceInstance(CloudServiceInstance serviceInstance) {
- assertSpaceProvided("create service instance");
- Assert.notNull(serviceInstance, "Service instance must not be null.");
- String syslogDrainUrl = StringUtils.hasText(serviceInstance.getSyslogDrainUrl()) ? serviceInstance.getSyslogDrainUrl() : "";
- delegate.serviceInstancesV3()
- .create(CreateServiceInstanceRequest.builder()
- .name(serviceInstance.getName())
- .metadata(serviceInstance.getV3Metadata())
- .type(ServiceInstanceType.USER_PROVIDED)
- .credentials(serviceInstance.getCredentials())
- .syslogDrainUrl(syslogDrainUrl)
- .tags(serviceInstance.getTags())
- .relationships(ServiceInstanceRelationships.builder()
- .space(buildToOneRelationship(
- getTargetSpaceGuid().toString()))
- .build())
- .build())
- .block();
- }
-
- @Override
- public void deleteApplication(String applicationName) {
- UUID applicationGuid = getRequiredApplicationGuid(applicationName);
- deleteApplication(applicationGuid);
- }
-
- private void deleteApplication(UUID applicationGuid) {
- delegate.applicationsV3()
- .delete(DeleteApplicationRequest.builder()
- .applicationId(applicationGuid.toString())
- .build())
- .flatMap(jobId -> JobV3Util.waitForCompletion(delegate, DELETE_JOB_TIMEOUT, jobId))
- .block();
- }
-
- @Override
- public void deleteDomain(String domainName) {
- assertSpaceProvided("delete domain");
- CloudDomain domain = findDomainByName(domainName, true);
- List routes = findRoutes(domain);
- if (!routes.isEmpty()) {
- throw new IllegalStateException("Unable to remove domain that is in use --" + " it has " + routes.size() + " routes.");
- }
- doDeleteDomain(getGuid(domain));
- }
-
- /**
- * Delete routes that do not have any application which is assigned to them.
- */
- @Override
- public void deleteOrphanedRoutes() {
- delegate.spacesV3()
- .deleteUnmappedRoutes(DeleteUnmappedRoutesRequest.builder()
- .spaceId(getTargetSpaceGuid().toString())
- .build())
- .flatMap(jobId -> JobV3Util.waitForCompletion(delegate, DELETE_JOB_TIMEOUT, jobId))
- .block();
- }
-
- @Override
- public void deleteRoute(String host, String domainName, String path) {
- assertSpaceProvided("delete route for domain");
- UUID routeGuid = getRouteGuid(getRequiredDomainGuid(domainName), host, path);
- if (routeGuid == null) {
- throw new CloudOperationException(HttpStatus.NOT_FOUND, "Not Found",
- "Host " + host + " not found for domain " + domainName + ".");
- }
- doDeleteRoute(routeGuid);
- }
-
- @Override
- public void deleteServiceInstance(String serviceInstanceName) {
- CloudServiceInstance serviceInstance = getServiceInstanceWithoutAuxiliaryContent(serviceInstanceName);
- doDeleteServiceInstance(serviceInstance.getGuid());
- }
-
- @Override
- public void deleteServiceInstance(CloudServiceInstance serviceInstance) {
- doDeleteServiceInstance(serviceInstance.getGuid());
- }
-
- @Override
- public String deleteServiceBroker(String name) {
- CloudServiceBroker broker = getServiceBroker(name);
- UUID guid = broker.getMetadata()
- .getGuid();
- return delegate.serviceBrokersV3()
- .delete(DeleteServiceBrokerRequest.builder()
- .serviceBrokerId(guid.toString())
- .build())
- .block();
- }
-
- @Override
- public Optional deleteServiceBinding(String serviceInstanceName, String serviceKeyName) {
- CloudServiceKey serviceKey = getServiceKey(serviceInstanceName, serviceKeyName);
- if (serviceKey == null) {
- throw new CloudOperationException(HttpStatus.NOT_FOUND, "Not Found", "Service key " + serviceKeyName + " not found.");
- }
- return doDeleteServiceBindings(List.of(serviceKey.getGuid())).stream()
- .findFirst();
- }
-
- @Override
- public CloudApplication getApplication(String applicationName) {
- return getApplication(applicationName, true);
- }
-
- @Override
- public CloudApplication getApplication(String applicationName, boolean required) {
- return findApplicationByName(applicationName, required);
- }
-
- @Override
- public UUID getApplicationGuid(String applicationName) {
- return getRequiredApplicationGuid(applicationName);
- }
-
- @Override
- public String getApplicationName(UUID applicationGuid) {
- // This will throw a CloudOperationException with a 404 if no app with given GUID is present
- return getApplicationByGuid(applicationGuid).block()
- .getName();
- }
-
- @Override
- public Map getApplicationEnvironment(UUID applicationGuid) {
- return delegate.applicationsV3()
- .getEnvironmentVariables(GetApplicationEnvironmentVariablesRequest.builder()
- .applicationId(applicationGuid.toString())
- .build())
- .map(GetApplicationEnvironmentVariablesResponse::getVars)
- .block();
- }
-
- @Override
- public Map getApplicationEnvironment(String applicationName) {
- UUID applicationGuid = getRequiredApplicationGuid(applicationName);
- return getApplicationEnvironment(applicationGuid);
- }
-
- @Override
- public List getApplicationEvents(String applicationName) {
- UUID applicationGuid = getRequiredApplicationGuid(applicationName);
- return getEventsByTarget(applicationGuid);
- }
-
- @Override
- public List getEventsByTarget(UUID uuid) {
- return findEventsByTarget(uuid.toString());
- }
-
- @Override
- public InstancesInfo getApplicationInstances(CloudApplication application) {
- if (application.getState()
- .equals(CloudApplication.State.STARTED)) {
- return findApplicationInstances(getGuid(application));
- }
- return ImmutableInstancesInfo.builder()
- .instances(Collections.emptyList())
- .build();
- }
-
- @Override
- public InstancesInfo getApplicationInstances(UUID applicationGuid) {
- return findApplicationInstances(applicationGuid);
- }
-
- @Override
- public CloudProcess getApplicationProcess(UUID applicationGuid) {
- return fetch(() -> Mono.just(getApplicationProcessResource(applicationGuid)), ImmutableRawCloudProcess::of);
- }
-
- @Override
- public List getApplicationRoutes(UUID applicationGuid) {
- return fetchList(() -> getRouteResourcesByAppGuid(applicationGuid), routeResource -> ImmutableRawCloudRoute.builder()
- .route(routeResource)
- .applicationGuid(
- applicationGuid)
- .build());
- }
-
- @Override
- public boolean getApplicationSshEnabled(UUID applicationGuid) {
- return delegate.applicationsV3()
- .getSshEnabled(GetApplicationSshEnabledRequest.builder()
- .applicationId(applicationGuid.toString())
- .build())
- .map(GetApplicationSshEnabledResponse::getEnabled)
- .defaultIfEmpty(false)
- .block();
- }
-
- @Override
- public Map getApplicationFeatures(UUID applicationGuid) {
- IntFunction pageRequestSupplier = page -> ListApplicationFeaturesRequest.builder()
- .applicationId(
- applicationGuid.toString())
- .page(page)
- .build();
- return PaginationUtils.requestClientV3Resources(page -> delegate.applicationsV3()
- .listFeatures(pageRequestSupplier.apply(page)))
- .collect(Collectors.toMap(ApplicationFeature::getName, ApplicationFeature::getEnabled))
- .block();
- }
-
- @Override
- public List getApplications() {
- return fetchList(this::getApplicationResources, application -> ImmutableRawCloudApplication.builder()
- .application(application)
- .space(target)
- .build());
- }
-
- @Override
- public List getApplicationsByMetadataLabelSelector(String labelSelector) {
- assertSpaceProvided("get applications");
- return fetchList(() -> getApplicationsByLabelSelector(labelSelector), application -> ImmutableRawCloudApplication.builder()
- .application(
- application)
- .space(target)
- .build());
- }
-
- private Flux extends Application> getApplicationsByLabelSelector(String labelSelector) {
- IntFunction pageRequestSupplier = page -> ListApplicationsRequest.builder()
- .spaceId(getTargetSpaceGuid().toString())
- .labelSelector(labelSelector)
- .page(page)
- .build();
- return PaginationUtils.requestClientV3Resources(page -> delegate.applicationsV3()
- .list(pageRequestSupplier.apply(page)));
- }
-
- @Override
- public CloudDomain getDefaultDomain() {
- return fetch(() -> getDefaultDomainResource(getTargetOrganizationGuid().toString()), ImmutableRawCloudDomain::of);
- }
-
- private Mono extends Domain> getDefaultDomainResource(String guid) {
- return delegate.organizationsV3()
- .getDefaultDomain(GetOrganizationDefaultDomainRequest.builder()
- .organizationId(guid)
- .build());
- }
-
- @Override
- public List getSharedDomains() {
- return fetchList(this::getSharedDomainResources, ImmutableRawCloudDomain::of);
- }
-
- @Override
- public List getDomains() {
- return fetchList(this::getDomainResources, ImmutableRawCloudDomain::of);
- }
-
- @Override
- public List getDomainsForOrganization() {
- assertSpaceProvided("access organization domains");
- return findDomainsByOrganizationGuid(getTargetOrganizationGuid());
- }
-
- @Override
- public List getPrivateDomains() {
- return fetchList(this::getPrivateDomainResources, ImmutableRawCloudDomain::of);
- }
-
- @Override
- public List getEvents() {
- return fetchList(this::getEventResources, ImmutableRawCloudEvent::of);
- }
-
- @Override
- public List getRoutes(String domainName) {
- assertSpaceProvided("get routes for domain");
- CloudDomain domain = findDomainByName(domainName, true);
- return findRoutes(domain);
- }
-
- @Override
- public UUID getRequiredServiceInstanceGuid(String name) {
- Resource serviceInstanceResource = getServiceInstanceByName(name).block();
- if (serviceInstanceResource == null) {
- throw new CloudOperationException(HttpStatus.NOT_FOUND, "Not Found", "Service instance " + name + " not found.");
- }
- return UUID.fromString(serviceInstanceResource.getId());
- }
-
- @Override
- public CloudServiceInstance getServiceInstance(String serviceInstanceName) {
- return getServiceInstance(serviceInstanceName, true);
- }
-
- @Override
- public CloudServiceInstance getServiceInstance(String serviceInstanceName, boolean required) {
- CloudServiceInstance serviceInstance = findServiceInstanceByName(serviceInstanceName);
- return getServiceInstanceIfRequired(serviceInstanceName, serviceInstance, required);
- }
-
- private CloudServiceInstance getServiceInstanceIfRequired(String serviceInstanceName, CloudServiceInstance serviceInstance,
- boolean required) {
- if (serviceInstance == null && required) {
- throw new CloudOperationException(HttpStatus.NOT_FOUND, "Not Found", "Service instance " + serviceInstanceName + " not found.");
- }
- return serviceInstance;
- }
-
- @Override
- public CloudServiceBinding getServiceBinding(UUID serviceBindingGuid) {
- // TODO: Refactor and use serviceBindingsV3.get() when https://github.com/cloudfoundry/cf-java-client/pull/1171 is merged and
- // released
- return fetch(() -> getServiceBindingResource(serviceBindingGuid), ImmutableRawCloudServiceBinding::of);
- }
-
- private Mono getServiceBindingResource(UUID serviceBindingGuid) {
- IntFunction pageRequestSupplier = page -> ListServiceBindingsRequest.builder()
- .page(page)
- .id(serviceBindingGuid.toString())
- .build();
- return PaginationUtils.requestClientV3Resources(page -> delegate.serviceBindingsV3()
- .list(pageRequestSupplier.apply(page)))
- .singleOrEmpty();
- }
-
- @Override
- public List getServiceAppBindings(UUID serviceInstanceGuid) {
- return fetchList(() -> getServiceBindingResourcesByServiceInstanceGuid(serviceInstanceGuid), ImmutableRawCloudServiceBinding::of);
- }
-
- @Override
- public List getAppBindings(UUID applicationGuid) {
- return fetchList(() -> getServiceBindingResourcesByApplicationGuid(applicationGuid), ImmutableRawCloudServiceBinding::of);
- }
-
- @Override
- public List getServiceBindingsForApplication(UUID applicationId, UUID serviceInstanceGuid) {
- return fetchList(() -> getServiceBindingResourcesByApplicationGuidAndServiceInstanceGuid(applicationId, serviceInstanceGuid),
- ImmutableRawCloudServiceBinding::of);
- }
-
- @Override
- public CloudServiceBroker getServiceBroker(String name) {
- return getServiceBroker(name, true);
- }
-
- @Override
- public CloudServiceBroker getServiceBroker(String name, boolean required) {
- CloudServiceBroker serviceBroker = findServiceBrokerByName(name);
- if (serviceBroker == null && required) {
- throw new CloudOperationException(HttpStatus.NOT_FOUND, "Not Found", "Service broker " + name + " not found.");
- }
- return serviceBroker;
- }
-
- @Override
- public List getServiceBrokers() {
- return fetchList(this::getServiceBrokerResources, ImmutableRawCloudServiceBroker::of);
- }
-
- @Override
- public CloudServiceKey getServiceKey(String serviceInstanceName, String serviceKeyName) {
- CloudServiceInstance serviceInstance = getServiceInstance(serviceInstanceName);
- return fetchWithAuxiliaryContent(() -> getServiceKeyResourceByNameAndServiceInstanceGuid(serviceKeyName, serviceInstance.getGuid()),
- serviceKey -> zipWithAuxiliaryServiceKeyContent(serviceKey, serviceInstance));
- }
-
- @Override
- public List getServiceKeys(String serviceInstanceName) {
- CloudServiceInstance serviceInstance = getServiceInstance(serviceInstanceName);
- return getServiceKeys(serviceInstance);
- }
-
- @Override
- public List getServiceKeysWithCredentials(String serviceInstanceName) {
- CloudServiceInstance serviceInstance = getServiceInstance(serviceInstanceName);
- return getServiceKeysWithCredentials(serviceInstance);
- }
-
- @Override
- public List getServiceKeys(CloudServiceInstance serviceInstance) {
- return fetchList(() -> getServiceKeyResource(serviceInstance), serviceKey -> ImmutableRawCloudServiceKey.builder()
- .serviceInstance(
- serviceInstance)
- .serviceBindingResource(
- serviceKey)
- .build());
- }
-
- @Override
- public List getServiceKeysWithCredentials(CloudServiceInstance serviceInstance) {
- return fetchListWithAuxiliaryContent(() -> getServiceKeyResource(serviceInstance),
- serviceKey -> zipWithAuxiliaryServiceKeyContent(serviceKey, serviceInstance));
- }
-
- private Mono> zipWithAuxiliaryServiceKeyContent(ServiceBindingResource key,
- CloudServiceInstance serviceInstance) {
- return getServiceKeyCredentials(key.getId()).map(credentials -> ImmutableRawCloudServiceKey.builder()
- .serviceBindingResource(key)
- .credentials(credentials)
- .serviceInstance(serviceInstance)
- .build());
- }
-
- private Mono