Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.sap.cloud.sdk.cloudplatform.connectivity;

import javax.annotation.Nullable;

/**
* Interface to be implemented by classes that can provide information about the behalf upon which an action is run.
*
* @since 4.27.0
*/
interface IsOnBehalfOf
{
/**
* Returns the behalf upon which an action is run.
*
* @return The behalf upon which an action is run, or {@code null} if no information about the behalf is available.
*/
@Nullable
default OnBehalfOf getOnBehalfOf()
{
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,8 @@ private Try<HttpClient> tryGetOrCreateHttpClient(
final Try<CacheKey> maybeKey = destination != null ? getCacheKey(destination) : getCacheKey();

if( maybeKey.isFailure() ) {
return Try
.failure(
new HttpClientInstantiationException(
"Failed to create cache key for HttpClient",
maybeKey.getCause()));
final String msg = "Failed to create cache key for HttpClient";
return Try.failure(new HttpClientInstantiationException(msg, maybeKey.getCause()));
}

final Cache<CacheKey, HttpClient> cache = maybeCache.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,85 @@

import com.google.common.annotations.Beta;

import lombok.Setter;
import lombok.experimental.Accessors;

/**
* Builder class for a default implementation of the {@link ApacheHttpClient5Factory} interface.
*
* @since 4.20.0
*/
@Accessors( fluent = true )
public class ApacheHttpClient5FactoryBuilder
{
/**
* The {@code Upgrade} header. Only {@link ProxyType#INTERNET} has the {@code Upgrade} header by default.
* <p>
* <b>{@link TlsUpgrade#DISABLED} only works for {@link ProxyType#INTERNET}</b>
* <p>
* <b>{@link TlsUpgrade#ENABLED} only works for {@link ProxyType#ON_PREMISE}</b>
*
* @since 5.14.0
*/
@Setter
@Nonnull
private Duration timeout = DefaultApacheHttpClient5Factory.DEFAULT_TIMEOUT;
private TlsUpgrade tlsUpgrade = TlsUpgrade.AUTOMATIC;
private int maxConnectionsTotal = DefaultApacheHttpClient5Factory.DEFAULT_MAX_CONNECTIONS_TOTAL;
private int maxConnectionsPerRoute = DefaultApacheHttpClient5Factory.DEFAULT_MAX_CONNECTIONS_PER_ROUTE;

/**
* The {@link ConnectionPoolSettings} to use for configuring connection pool managers and request timeouts.
* <p>
* This replaces any previously configured settings from {@link #timeout(Duration)},
* {@link #maxConnectionsTotal(int)}, or {@link #maxConnectionsPerRoute(int)}.
* </p>
* <p>
* This is an <b>optional</b> parameter. By default, settings use the default values.
* </p>
*
* @see DefaultConnectionPoolSettings#ofDefaults()
* @see DefaultConnectionPoolSettings#builder()
* @since 5.27.0
*/
@Setter( onMethod_ = @Beta )
@Nonnull
private DefaultConnectionPoolSettings settings = DefaultConnectionPoolSettings.ofDefaults();

/**
* A custom {@link ConnectionPoolManagerProvider} for creating and managing HTTP connection pool managers.
* <p>
* This allows customization of how connection managers are created and cached. Use
* {@link ConnectionPoolManagerProviders} to obtain pre-built implementations with common caching strategies:
* </p>
* <ul>
* <li>{@link ConnectionPoolManagerProviders#noCache()} - No caching (default behavior)</li>
* <li>{@link ConnectionPoolManagerProviders#byTenant()} - Cache by current tenant</li>
* <li>{@link ConnectionPoolManagerProviders#byDestinationName()} - Cache by destination name</li>
* <li>{@link ConnectionPoolManagerProviders#global()} - Single global connection manager</li>
* <li>{@link ConnectionPoolManagerProviders#withCacheKey(java.util.function.Function)} - Custom cache key</li>
* </ul>
* <p>
* This is an <b>optional</b> parameter. By default, a new connection manager is created for each HTTP client
* without caching.
* </p>
*
* <h3>Example Usage</h3>
*
* <pre>
* {@code
* // Cache connection managers by tenant to reduce memory consumption
* ApacheHttpClient5Factory factory =
* new ApacheHttpClient5FactoryBuilder()
* .connectionPoolManagerProvider(ConnectionPoolManagerProviders.byTenant())
* .build();
* }
* </pre>
*
* @see ConnectionPoolManagerProvider
* @see ConnectionPoolManagerProviders
* @since 5.27.0
*/
@Setter( onMethod_ = @Beta )
@Nonnull
private ConnectionPoolManagerProvider connectionPoolManagerProvider = ConnectionPoolManagerProviders.noCache();

/**
* Enum to control the automatic TLS upgrade feature for insecure connections.
Expand Down Expand Up @@ -88,7 +155,8 @@ public ApacheHttpClient5FactoryBuilder timeoutInMilliseconds( final int timeoutI
@Nonnull
public ApacheHttpClient5FactoryBuilder timeout( @Nonnull final Duration timeout )
{
this.timeout = timeout;
settings =
settings.withConnectTimeout(timeout).withSocketTimeout(timeout).withConnectionRequestTimeout(timeout);
return this;
}

Expand All @@ -106,23 +174,7 @@ public ApacheHttpClient5FactoryBuilder timeout( @Nonnull final Duration timeout
@Nonnull
public ApacheHttpClient5FactoryBuilder maxConnectionsTotal( final int maxConnectionsTotal )
{
this.maxConnectionsTotal = maxConnectionsTotal;
return this;
}

/**
* Sets the {@code Upgrade} header. Only {@link ProxyType#INTERNET} has the {@code Upgrade} header by default.
* <p>
* <b>{@link TlsUpgrade#DISABLED} only works for {@link ProxyType#INTERNET}</b>
* <p>
* <b>{@link TlsUpgrade#ENABLED} only works for {@link ProxyType#ON_PREMISE}</b>
*
* @since 5.14.0
*/
@Nonnull
public ApacheHttpClient5FactoryBuilder tlsUpgrade( @Nonnull final TlsUpgrade tlsUpgrade )
{
this.tlsUpgrade = tlsUpgrade;
settings = settings.withMaxConnectionsTotal(maxConnectionsTotal);
return this;
}

Expand All @@ -141,7 +193,7 @@ public ApacheHttpClient5FactoryBuilder tlsUpgrade( @Nonnull final TlsUpgrade tls
@Nonnull
public ApacheHttpClient5FactoryBuilder maxConnectionsPerRoute( final int maxConnectionsPerRoute )
{
this.maxConnectionsPerRoute = maxConnectionsPerRoute;
settings = settings.withMaxConnectionsPerRoute(maxConnectionsPerRoute);
return this;
}

Expand All @@ -153,11 +205,6 @@ public ApacheHttpClient5FactoryBuilder maxConnectionsPerRoute( final int maxConn
@Nonnull
public ApacheHttpClient5Factory build()
{
return new DefaultApacheHttpClient5Factory(
timeout,
maxConnectionsTotal,
maxConnectionsPerRoute,
null,
tlsUpgrade);
return new DefaultApacheHttpClient5Factory(settings, connectionPoolManagerProvider, null, tlsUpgrade);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.sap.cloud.sdk.cloudplatform.connectivity;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.apache.hc.client5.http.io.HttpClientConnectionManager;

import com.google.common.annotations.Beta;
import com.sap.cloud.sdk.cloudplatform.connectivity.exception.HttpClientInstantiationException;

/**
* Functional interface for creating or retrieving {@link HttpClientConnectionManager} instances.
* <p>
* Implementations can choose to cache connection managers based on various strategies (e.g., by tenant, by destination
* name, globally) to reduce memory consumption. Each connection manager typically consumes around 100KB of memory.
* </p>
* <p>
* Use {@link ConnectionPoolManagerProviders} to obtain pre-built implementations with common caching strategies.
* </p>
*
* <h2>Example Usage</h2>
*
* <pre>
* {@code
* // Simple lambda implementation (no caching)
* ConnectionPoolManagerProvider provider =
* ( settings, dest ) -> PoolingHttpClientConnectionManagerBuilder
* .create()
* .setMaxConnTotal(settings.maxConnectionsTotal())
* .build();
*
* // Using pre-built providers
* ConnectionPoolManagerProvider cachingProvider = ConnectionPoolManagerProviders.byTenant();
* }
* </pre>
*
* @see ConnectionPoolManagerProviders
* @see ApacheHttpClient5FactoryBuilder#connectionPoolManagerProvider(ConnectionPoolManagerProvider)
* @since 5.27.0
*/
@Beta
@FunctionalInterface
public interface ConnectionPoolManagerProvider
{
/**
* Gets or creates an {@link HttpClientConnectionManager} for the given destination.
* <p>
* Implementations may cache connection managers based on destination properties, tenant context, or other criteria.
* The settings parameter provides the configuration for creating new connection managers.
* </p>
*
* @param settings
* The connection pool settings to use when creating a new connection manager.
* @param destination
* The destination properties to create the connection manager for, or {@code null} for a generic
* connection manager.
* @return A connection manager suitable for the given destination.
* @throws HttpClientInstantiationException
* If the connection manager cannot be created.
*/
@Nonnull
HttpClientConnectionManager getConnectionManager(
@Nonnull ConnectionPoolSettings settings,
@Nullable HttpDestinationProperties destination )
throws HttpClientInstantiationException;
}
Loading