diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/AbstractPayloadCachingRootProvider.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/AbstractPayloadCachingRootProvider.java index 5bdad93884d..661696d7e96 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/AbstractPayloadCachingRootProvider.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/AbstractPayloadCachingRootProvider.java @@ -46,8 +46,11 @@ protected final Mono doGetRoot(String key, ConnectionContext conn abstract ObjectMapper getObjectMapper(); private Mono> getPayload(ConnectionContext connectionContext) { - return doGetPayload(connectionContext) - .cache(); + Mono> cached = doGetPayload(connectionContext); + + return connectionContext.getCacheDuration() + .map(cached::cache) + .orElseGet(cached::cache); } } diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/AbstractRootProvider.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/AbstractRootProvider.java index dbee53c48e4..5c216b94e45 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/AbstractRootProvider.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/AbstractRootProvider.java @@ -52,18 +52,24 @@ public final void checkForValidApiHost() { @Override public final Mono getRoot(ConnectionContext connectionContext) { - return doGetRoot(connectionContext) + Mono cached = doGetRoot(connectionContext) .delayUntil(uri -> trust(uri.getHost(), uri.getPort(), connectionContext)) - .map(UriComponents::toUriString) - .cache(); + .map(UriComponents::toUriString); + + return connectionContext.getCacheDuration() + .map(cached::cache) + .orElseGet(cached::cache); } @Override public final Mono getRoot(String key, ConnectionContext connectionContext) { - return doGetRoot(key, connectionContext) + Mono cached = doGetRoot(key, connectionContext) .delayUntil(uri -> trust(uri.getHost(), uri.getPort(), connectionContext)) - .map(UriComponents::toUriString) - .cache(); + .map(UriComponents::toUriString); + + return connectionContext.getCacheDuration() + .map(cached::cache) + .orElseGet(cached::cache); } protected abstract Mono doGetRoot(ConnectionContext connectionContext); diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/ConnectionContext.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/ConnectionContext.java index 0813f29fb0a..ca792aa44f6 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/ConnectionContext.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/ConnectionContext.java @@ -20,11 +20,19 @@ import reactor.core.publisher.Mono; import reactor.ipc.netty.http.client.HttpClient; +import java.time.Duration; +import java.util.Optional; + /** * Common, reusable, connection context */ public interface ConnectionContext { + /** + * The duration that stable responses like the payload of the API root should be cached + */ + Optional getCacheDuration(); + /** * The {@link HttpClient} to use */ diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/_DefaultConnectionContext.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/_DefaultConnectionContext.java index 9d968a1bd8d..eaa42e414d1 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/_DefaultConnectionContext.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/_DefaultConnectionContext.java @@ -71,6 +71,9 @@ public final void dispose() { getThreadPool().dispose(); } + @Override + public abstract Optional getCacheDuration(); + /** * The number of connections to use when processing requests and responses. Setting this to `null` disables connection pooling. */ @@ -97,9 +100,8 @@ public HttpClient getHttpClient() { getConnectTimeout().ifPresent(socketTimeout -> options.option(CONNECT_TIMEOUT_MILLIS, (int) socketTimeout.toMillis())); getKeepAlive().ifPresent(keepAlive -> options.option(SO_KEEPALIVE, keepAlive)); getSslHandshakeTimeout().ifPresent(options::sslHandshakeTimeout); -// TODO: Add back once these options show up in 0.7.0 -// getSslCloseNotifyFlushTimeout().ifPresent(options::sslCloseNotifyFlushTimeout); -// getSslCloseNotifyReadTimeout().ifPresent(options::sslCloseNotifyReadTimeout); + getSslCloseNotifyFlushTimeout().ifPresent(options::sslCloseNotifyFlushTimeout); + getSslCloseNotifyReadTimeout().ifPresent(options::sslCloseNotifyReadTimeout); getProxyConfiguration().ifPresent(c -> c.configure(options)); }); } diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/AbstractUaaTokenProvider.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/AbstractUaaTokenProvider.java index 231e8a75ea3..227e437add7 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/AbstractUaaTokenProvider.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/tokenprovider/AbstractUaaTokenProvider.java @@ -257,14 +257,17 @@ private Mono requestToken(ConnectionContext connectionContex } private Mono token(ConnectionContext connectionContext) { - return this.refreshTokens.getOrDefault(connectionContext, Mono.empty()) + Mono cached = this.refreshTokens.getOrDefault(connectionContext, Mono.empty()) .flatMap(refreshToken -> refreshToken(connectionContext, refreshToken) .doOnSubscribe(s -> LOGGER.debug("Negotiating using refresh token"))) .switchIfEmpty(primaryToken(connectionContext) .doOnSubscribe(s -> LOGGER.debug("Negotiating using token provider"))) .transform(ErrorPayloadMapper.fallback()) - .transform(extractTokens(connectionContext)) - .cache() + .transform(extractTokens(connectionContext)); + + return connectionContext.getCacheDuration() + .map(cached::cache) + .orElseGet(cached::cache) .checkpoint(); } diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/uaa/_ReactorUaaClient.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/uaa/_ReactorUaaClient.java index 034cbcbd69d..ada85ac2558 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/uaa/_ReactorUaaClient.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/uaa/_ReactorUaaClient.java @@ -107,9 +107,12 @@ public Users users() { @Value.Default Mono getRoot() { - return getConnectionContext().getRootProvider().getRoot("uaa", getConnectionContext()) - .map(getIdentityZoneEndpoint(getIdentityZoneSubdomain())) - .cache(); + Mono cached = getConnectionContext().getRootProvider().getRoot("uaa", getConnectionContext()) + .map(getIdentityZoneEndpoint(getIdentityZoneSubdomain())); + + return getConnectionContext().getCacheDuration() + .map(cached::cache) + .orElseGet(cached::cache); } /** diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java index e712a645bec..ef2ff840cab 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java @@ -56,6 +56,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; import java.util.NoSuchElementException; import java.util.Optional; @@ -137,6 +138,11 @@ public Stacks stacks() { return new DefaultStacks(getCloudFoundryClientPublisher()); } + /** + * The duration that stable responses like the organization and space id should be cached + */ + abstract Optional getCacheDuration(); + /** * The {@link CloudFoundryClient} to use for operations functionality */ @@ -174,9 +180,12 @@ Mono getOrganizationId() { String organization = getOrganization(); if (hasText(organization)) { - return getOrganization(getCloudFoundryClientPublisher(), organization) - .map(ResourceUtils::getId) - .cache(); + Mono cached = getOrganization(getCloudFoundryClientPublisher(), organization) + .map(ResourceUtils::getId); + + return getCacheDuration() + .map(cached::cache) + .orElseGet(cached::cache); } else { return Mono.error(new IllegalStateException("No organization targeted")); } @@ -206,10 +215,13 @@ Mono getSpaceId() { String space = getSpace(); if (hasText(getSpace())) { - return getOrganizationId() + Mono cached = getOrganizationId() .flatMap(organizationId -> getSpace(getCloudFoundryClientPublisher(), organizationId, space)) - .map(ResourceUtils::getId) - .cache(); + .map(ResourceUtils::getId); + + return getCacheDuration() + .map(cached::cache) + .orElseGet(cached::cache); } else { return Mono.error(new IllegalStateException("No space targeted")); }