From cc94b53da2f63ebd605619500f8366513f6a7d7d Mon Sep 17 00:00:00 2001 From: Rob Rudin Date: Mon, 22 Sep 2025 12:43:10 -0400 Subject: [PATCH] MLE-24405 Cleaned up RESTServices API This internal API had several unused methods. In addition, application of the client configurators happens in OkHttpServices now. That removes as much OkHttp stuff as possible from DatabaseClientFactory. This will greatly simplify shifting to the JDK HTTP client some time in the future. --- .../client/DatabaseClientFactory.java | 37 +--- .../OkHttpClientBuilderFactory.java | 4 +- .../client/impl/DatabaseClientImpl.java | 2 - .../marklogic/client/impl/OkHttpServices.java | 171 +++++------------- .../marklogic/client/impl/RESTServices.java | 56 ++---- .../client/impl/okhttp/OkHttpUtil.java | 10 +- 6 files changed, 81 insertions(+), 199 deletions(-) diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientFactory.java b/marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientFactory.java index 8406d7213..10bb1c69c 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientFactory.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientFactory.java @@ -7,7 +7,6 @@ import com.marklogic.client.impl.*; import com.marklogic.client.io.marker.ContentHandle; import com.marklogic.client.io.marker.ContentHandleFactory; -import okhttp3.OkHttpClient; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; @@ -31,7 +30,7 @@ */ public class DatabaseClientFactory { - static private List> clientConfigurators = Collections.synchronizedList(new ArrayList<>()); + static private List clientConfigurators = Collections.synchronizedList(new ArrayList<>()); static private HandleFactoryRegistry handleRegistry = HandleFactoryRegistryImpl.newDefault(); @@ -1329,7 +1328,6 @@ static public DatabaseClient newClient(String host, int port, String database, static public DatabaseClient newClient(String host, int port, String basePath, String database, SecurityContext securityContext, DatabaseClient.ConnectionType connectionType) { - RESTServices services = new OkHttpServices(); // As of 6.1.0, the following optimization is made as it's guaranteed that if the user is connecting to a // Progress Data Cloud instance, then port 443 will be used. Every path for constructing a DatabaseClient goes through // this method, ensuring that this optimization will always be applied, and thus freeing the user from having to @@ -1337,25 +1335,10 @@ static public DatabaseClient newClient(String host, int port, String basePath, S if (securityContext instanceof MarkLogicCloudAuthContext || securityContext instanceof ProgressDataCloudAuthContext) { port = 443; } - services.connect(host, port, basePath, database, securityContext); - - if (clientConfigurators != null) { - clientConfigurators.forEach(configurator -> { - if (configurator instanceof OkHttpClientConfigurator) { - OkHttpClient okHttpClient = (OkHttpClient) services.getClientImplementation(); - Objects.requireNonNull(okHttpClient); - OkHttpClient.Builder clientBuilder = okHttpClient.newBuilder(); - ((OkHttpClientConfigurator) configurator).configure(clientBuilder); - ((OkHttpServices) services).setClientImplementation(clientBuilder.build()); - } else { - throw new IllegalArgumentException("A ClientConfigurator must implement OkHttpClientConfigurator"); - } - }); - } - DatabaseClientImpl client = new DatabaseClientImpl( - services, host, port, basePath, database, securityContext, connectionType - ); + OkHttpServices.ConnectionConfig config = new OkHttpServices.ConnectionConfig(host, port, basePath, database, securityContext, clientConfigurators); + RESTServices services = new OkHttpServices(config); + DatabaseClientImpl client = new DatabaseClientImpl(services, host, port, basePath, database, securityContext, connectionType); client.setHandleRegistry(getHandleRegistry().copy()); return client; } @@ -1397,13 +1380,13 @@ static public void registerDefaultHandles() { * @param configurator the listener for configuring the communication library */ static public void addConfigurator(ClientConfigurator configurator) { - if (!OkHttpClientConfigurator.class.isInstance(configurator)) { - throw new IllegalArgumentException( - "Configurator must implement OkHttpClientConfigurator" - ); - } + if (!OkHttpClientConfigurator.class.isInstance(configurator)) { + throw new IllegalArgumentException( + "Configurator must implement OkHttpClientConfigurator" + ); + } - clientConfigurators.add(configurator); + clientConfigurators.add((OkHttpClientConfigurator) configurator); } /** diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/extra/okhttpclient/OkHttpClientBuilderFactory.java b/marklogic-client-api/src/main/java/com/marklogic/client/extra/okhttpclient/OkHttpClientBuilderFactory.java index fcd0c022f..995a5392b 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/extra/okhttpclient/OkHttpClientBuilderFactory.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/extra/okhttpclient/OkHttpClientBuilderFactory.java @@ -7,6 +7,8 @@ import com.marklogic.client.impl.okhttp.OkHttpUtil; import okhttp3.OkHttpClient; +import java.util.ArrayList; + /** * Exposes the mechanism for constructing an {@code OkHttpClient.Builder} in the same fashion as when a * {@code DatabaseClient} is constructed. Primarily intended for reuse in the ml-app-deployer library. If the @@ -17,6 +19,6 @@ public interface OkHttpClientBuilderFactory { static OkHttpClient.Builder newOkHttpClientBuilder(String host, DatabaseClientFactory.SecurityContext securityContext) { - return OkHttpUtil.newOkHttpClientBuilder(host, securityContext); + return OkHttpUtil.newOkHttpClientBuilder(host, securityContext, new ArrayList<>()); } } diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/impl/DatabaseClientImpl.java b/marklogic-client-api/src/main/java/com/marklogic/client/impl/DatabaseClientImpl.java index a61b7df47..7a144b2dd 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/impl/DatabaseClientImpl.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/impl/DatabaseClientImpl.java @@ -60,8 +60,6 @@ public DatabaseClientImpl(RESTServices services, String host, int port, String b this.database = database; this.securityContext = securityContext; this.connectionType = connectionType; - - services.setDatabaseClient(this); } public long getServerVersion() { diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/impl/OkHttpServices.java b/marklogic-client-api/src/main/java/com/marklogic/client/impl/OkHttpServices.java index dd8a81bc0..29017c2c2 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/impl/OkHttpServices.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/impl/OkHttpServices.java @@ -18,6 +18,7 @@ import com.marklogic.client.document.DocumentManager.Metadata; import com.marklogic.client.eval.EvalResult; import com.marklogic.client.eval.EvalResultIterator; +import com.marklogic.client.extra.okhttpclient.OkHttpClientConfigurator; import com.marklogic.client.impl.okhttp.HttpUrlBuilder; import com.marklogic.client.impl.okhttp.OkHttpUtil; import com.marklogic.client.impl.okhttp.PartIterator; @@ -74,10 +75,10 @@ public class OkHttpServices implements RESTServices { static final private Logger logger = LoggerFactory.getLogger(OkHttpServices.class); - static final public String OKHTTP_LOGGINGINTERCEPTOR_LEVEL = "com.marklogic.client.okhttp.httplogginginterceptor.level"; - static final public String OKHTTP_LOGGINGINTERCEPTOR_OUTPUT = "com.marklogic.client.okhttp.httplogginginterceptor.output"; + private static final String OKHTTP_LOGGINGINTERCEPTOR_LEVEL = "com.marklogic.client.okhttp.httplogginginterceptor.level"; + private static final String OKHTTP_LOGGINGINTERCEPTOR_OUTPUT = "com.marklogic.client.okhttp.httplogginginterceptor.output"; - static final private String DOCUMENT_URI_PREFIX = "/documents?uri="; + private static final String DOCUMENT_URI_PREFIX = "/documents?uri="; static final private int DELAY_FLOOR = 125; static final private int DELAY_CEILING = 2000; @@ -88,10 +89,14 @@ public class OkHttpServices implements RESTServices { private final static MediaType URLENCODED_MIME_TYPE = MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8"); private final static String UTF8_ID = StandardCharsets.UTF_8.toString(); - private DatabaseClient databaseClient; private String database = null; private HttpUrl baseUri; - private OkHttpClient client; + + // This should really be final, but given the history of this class and the former "connect()" method that meant + // the client was created in the constructor, this is being kept as non-final so it can be assigned a value of null + // on release. + private OkHttpClient okHttpClient; + private boolean released = false; private final Random randRetry = new Random(); @@ -114,25 +119,16 @@ static protected class ThreadState { private final ThreadLocal threadState = ThreadLocal.withInitial(() -> new ThreadState(checkFirstRequest)); - public OkHttpServices() { + public record ConnectionConfig(String host, int port, String basePath, String database, + SecurityContext securityContext, List clientConfigurators) { + } + + public OkHttpServices(ConnectionConfig connectionConfig) { retryStatus.add(STATUS_BAD_GATEWAY); retryStatus.add(STATUS_SERVICE_UNAVAILABLE); retryStatus.add(STATUS_GATEWAY_TIMEOUT); - } - @Override - public Set getRetryStatus() { - return retryStatus; - } - - @Override - public int getMaxDelay() { - return maxDelay; - } - - @Override - public void setMaxDelay(int maxDelay) { - this.maxDelay = maxDelay; + this.okHttpClient = connect(connectionConfig); } private FailedRequest extractErrorFields(Response response) { @@ -176,18 +172,19 @@ private FailedRequest extractErrorFields(Response response) { } } - @Override - public void connect(String host, int port, String basePath, String database, SecurityContext securityContext) { - if (host == null) + private OkHttpClient connect(ConnectionConfig config) { + if (config.host == null) { throw new IllegalArgumentException("No host provided"); - if (securityContext == null) + } + if (config.securityContext == null) { throw new IllegalArgumentException("No security context provided"); + } - this.checkFirstRequest = securityContext instanceof DigestAuthContext; - this.database = database; - this.baseUri = HttpUrlBuilder.newBaseUrl(host, port, basePath, securityContext.getSSLContext()); + this.checkFirstRequest = config.securityContext instanceof DigestAuthContext; + this.database = config.database; + this.baseUri = HttpUrlBuilder.newBaseUrl(config.host, config.port, config.basePath, config.securityContext.getSSLContext()); - OkHttpClient.Builder clientBuilder = OkHttpUtil.newOkHttpClientBuilder(host, securityContext); + OkHttpClient.Builder clientBuilder = OkHttpUtil.newOkHttpClientBuilder(config.host, config.securityContext, config.clientConfigurators); Properties props = System.getProperties(); if (props.containsKey(OKHTTP_LOGGINGINTERCEPTOR_LEVEL)) { @@ -195,15 +192,12 @@ public void connect(String host, int port, String basePath, String database, Sec } this.configureDelayAndRetry(props); - this.client = clientBuilder.build(); + return clientBuilder.build(); } /** * Based on the given properties, add a network interceptor to the given OkHttpClient.Builder to log HTTP * traffic. - * - * @param clientBuilder - * @param props */ private void configureOkHttpLogging(OkHttpClient.Builder clientBuilder, Properties props) { final boolean useLogger = "LOGGER".equalsIgnoreCase(props.getProperty(OKHTTP_LOGGINGINTERCEPTOR_OUTPUT)); @@ -244,40 +238,21 @@ private void configureDelayAndRetry(Properties props) { } } - @Override - public DatabaseClient getDatabaseClient() { - return databaseClient; - } - - @Override - public void setDatabaseClient(DatabaseClient client) { - this.databaseClient = client; - } - - private OkHttpClient getConnection() { - if (client != null) { - return client; - } else if (released) { - throw new IllegalStateException( - "You cannot use this connected object anymore--connection has already been released"); - } else { - throw new MarkLogicInternalException("Cannot proceed--connection is null for unknown reason"); - } - } - @Override public void release() { - if (client == null) return; + if (released || okHttpClient == null) { + return; + } try { released = true; - client.dispatcher().executorService().shutdownNow(); + okHttpClient.dispatcher().executorService().shutdownNow(); } finally { try { - if (client.cache() != null) client.cache().close(); + if (okHttpClient.cache() != null) okHttpClient.cache().close(); } catch (IOException e) { throw new MarkLogicIOException(e); } finally { - client = null; + okHttpClient = null; logger.debug("Releasing connection"); } } @@ -491,8 +466,13 @@ private Response sendRequestOnce(Request.Builder requestBldr) { } private Response sendRequestOnce(Request request) { + if (released) { + throw new IllegalStateException( + "You cannot use this connected object anymore--connection has already been released"); + } + try { - return getConnection().newCall(request).execute(); + return okHttpClient.newCall(request).execute(); } catch (IOException e) { if (e instanceof SSLException) { String message = e.getMessage(); @@ -2591,25 +2571,6 @@ public Response apply(Request.Builder funcBuilder) { return (reqlog != null) ? reqlog.copyContent(entity) : entity; } - @Override - public void postValue(RequestLogger reqlog, String type, String key, - String mimetype, Object value) - throws ResourceNotResendableException, ForbiddenUserException, FailedRequestException { - logger.debug("Posting {}/{}", type, key); - - putPostValueImpl(reqlog, "post", type, key, null, mimetype, value, STATUS_CREATED); - } - - @Override - public void postValue(RequestLogger reqlog, String type, String key, - RequestParameters extraParams) - throws ResourceNotResendableException, ForbiddenUserException, FailedRequestException { - logger.debug("Posting {}/{}", type, key); - - putPostValueImpl(reqlog, "post", type, key, extraParams, null, null, STATUS_NO_CONTENT); - } - - @Override public void putValue(RequestLogger reqlog, String type, String key, String mimetype, Object value) @@ -2795,42 +2756,6 @@ public Response apply(Request.Builder funcBuilder) { logRequest(reqlog, "deleted %s value with %s key", type, key); } - @Override - public void deleteValues(RequestLogger reqlog, String type) - throws ForbiddenUserException, FailedRequestException { - logger.debug("Deleting {}", type); - - Request.Builder requestBldr = setupRequest(type, null); - requestBldr = addTelemetryAgentId(requestBldr); - - Function doDeleteFunction = new Function() { - public Response apply(Request.Builder funcBuilder) { - return sendRequestOnce(funcBuilder.delete().build()); - } - }; - Response response = sendRequestWithRetry(requestBldr, doDeleteFunction, null); - int status = response.code(); - if (status == STATUS_FORBIDDEN) { - throw new ForbiddenUserException("User is not allowed to delete " - + type, extractErrorFields(response)); - } - if (status != STATUS_NO_CONTENT) { - throw new FailedRequestException("delete failed: " - + getReasonPhrase(response), extractErrorFields(response)); - } - closeResponse(response); - - logRequest(reqlog, "deleted %s values", type); - } - - @Override - public R getSystemSchema(RequestLogger reqlog, String schemaName, R output) - throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException { - RequestParameters params = new RequestParameters(); - params.add("system", schemaName); - return getResource(reqlog, "internal/schemas", null, params, output); - } - @Override public R uris(RequestLogger reqlog, String method, SearchQueryDefinition qdef, Boolean filtered, long start, String afterUri, long pageLength, String forestName, R output @@ -3352,7 +3277,7 @@ public R postResou } @Override - public R postBulkDocuments( + public void postBulkDocuments( RequestLogger reqlog, DocumentWriteSet writeSet, ServerTransform transform, Transaction transaction, Format defaultFormat, R output, String temporalCollection, String extraContentDispositionParams) @@ -3411,7 +3336,7 @@ public R postBulkDocuments( transform.merge(params); } if (temporalCollection != null) params.add("temporal-collection", temporalCollection); - return postResource(reqlog, "documents", transaction, params, + postResource(reqlog, "documents", transaction, params, (AbstractWriteHandle[]) writeHandles.toArray(new AbstractWriteHandle[0]), (RequestParameters[]) headerList.toArray(new RequestParameters[0]), output); @@ -4843,12 +4768,7 @@ public T getContentAs(Class as) { @Override public OkHttpClient getClientImplementation() { - if (client == null) return null; - return client; - } - - public void setClientImplementation(OkHttpClient client) { - this.client = client; + return okHttpClient; } @Override @@ -5153,12 +5073,12 @@ public R getGraphUris(RequestLogger reqlog, R out } @Override - public R readGraph(RequestLogger reqlog, String uri, R output, + public void readGraph(RequestLogger reqlog, String uri, R output, Transaction transaction) throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException { RequestParameters params = new RequestParameters(); addGraphUriParam(params, uri); - return getResource(reqlog, "graphs", transaction, params, output); + getResource(reqlog, "graphs", transaction, params, output); } @Override @@ -5235,12 +5155,11 @@ public void mergePermissions(RequestLogger reqlog, String uri, } @Override - public Object deleteGraph(RequestLogger reqlog, String uri, Transaction transaction) + public void deleteGraph(RequestLogger reqlog, String uri, Transaction transaction) throws ForbiddenUserException, FailedRequestException { RequestParameters params = new RequestParameters(); addGraphUriParam(params, uri); - return deleteResource(reqlog, "graphs", transaction, params, null); - + deleteResource(reqlog, "graphs", transaction, params, null); } @Override diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/impl/RESTServices.java b/marklogic-client-api/src/main/java/com/marklogic/client/impl/RESTServices.java index 7750361c6..0f643daa7 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/impl/RESTServices.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/impl/RESTServices.java @@ -3,34 +3,15 @@ */ package com.marklogic.client.impl; -import java.io.InputStream; -import java.io.Reader; -import java.util.Calendar; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; - -import com.marklogic.client.DatabaseClient; -import com.marklogic.client.DatabaseClientFactory.SecurityContext; -import com.marklogic.client.FailedRequestException; -import com.marklogic.client.ForbiddenUserException; -import com.marklogic.client.ResourceNotFoundException; -import com.marklogic.client.ResourceNotResendableException; -import com.marklogic.client.SessionState; -import com.marklogic.client.Transaction; +import com.marklogic.client.DatabaseClient.ConnectionResult; +import com.marklogic.client.*; import com.marklogic.client.bitemporal.TemporalDescriptor; import com.marklogic.client.bitemporal.TemporalDocumentManager.ProtectionLevel; -import com.marklogic.client.document.DocumentDescriptor; +import com.marklogic.client.document.*; import com.marklogic.client.document.DocumentManager.Metadata; -import com.marklogic.client.document.DocumentPage; -import com.marklogic.client.document.DocumentUriTemplate; -import com.marklogic.client.document.DocumentWriteSet; -import com.marklogic.client.document.ServerTransform; import com.marklogic.client.eval.EvalResultIterator; import com.marklogic.client.extensions.ResourceServices.ServiceResult; import com.marklogic.client.extensions.ResourceServices.ServiceResultIterator; -import com.marklogic.client.DatabaseClient.ConnectionResult; import com.marklogic.client.io.BytesHandle; import com.marklogic.client.io.Format; import com.marklogic.client.io.InputStreamHandle; @@ -44,6 +25,14 @@ import com.marklogic.client.util.RequestLogger; import com.marklogic.client.util.RequestParameters; +import java.io.InputStream; +import java.io.Reader; +import java.util.Calendar; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + public interface RESTServices { String AUTHORIZATION_TYPE_SAML = "SAML"; @@ -78,7 +67,6 @@ public interface RESTServices { String MIMETYPE_APPLICATION_JSON = "application/json"; String MIMETYPE_APPLICATION_XML = "application/xml"; String MIMETYPE_MULTIPART_MIXED = "multipart/mixed"; - String MIMETYPE_MULTIPART_FORM = "multipart/form-data"; int STATUS_OK = 200; int STATUS_CREATED = 201; @@ -98,13 +86,6 @@ public interface RESTServices { String MAX_DELAY_PROP = "com.marklogic.client.maximumRetrySeconds"; String MIN_RETRY_PROP = "com.marklogic.client.minimumRetries"; - Set getRetryStatus(); - int getMaxDelay(); - void setMaxDelay(int maxDelay); - - void connect(String host, int port, String basePath, String database, SecurityContext securityContext); - DatabaseClient getDatabaseClient(); - void setDatabaseClient(DatabaseClient client); void release(); TemporalDescriptor deleteDocument(RequestLogger logger, DocumentDescriptor desc, Transaction transaction, @@ -129,7 +110,7 @@ DocumentPage getBulkDocuments(RequestLogger logger, long serverTimestamp, Search RequestParameters extraParams, String forestName) throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException; - T postBulkDocuments(RequestLogger logger, DocumentWriteSet writeSet, + void postBulkDocuments(RequestLogger logger, DocumentWriteSet writeSet, ServerTransform transform, Transaction transaction, Format defaultFormat, T output, String temporalCollection, String extraContentDispositionParams) throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException; @@ -188,10 +169,6 @@ T getValues(RequestLogger logger, String type, String mimetype, Class as) T getValues(RequestLogger reqlog, String type, RequestParameters extraParams, String mimetype, Class as) throws ForbiddenUserException, FailedRequestException; - void postValue(RequestLogger logger, String type, String key, String mimetype, Object value) - throws ResourceNotResendableException, ForbiddenUserException, FailedRequestException; - void postValue(RequestLogger reqlog, String type, String key, RequestParameters extraParams) - throws ResourceNotResendableException, ForbiddenUserException, FailedRequestException; void putValue(RequestLogger logger, String type, String key, String mimetype, Object value) throws ResourceNotFoundException, ResourceNotResendableException, ForbiddenUserException, @@ -202,11 +179,6 @@ void putValue(RequestLogger logger, String type, String key, RequestParameters e FailedRequestException; void deleteValue(RequestLogger logger, String type, String key) throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException; - void deleteValues(RequestLogger logger, String type) - throws ForbiddenUserException, FailedRequestException; - - R getSystemSchema(RequestLogger reqlog, String schemaName, R output) - throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException; R uris(RequestLogger reqlog, String method, SearchQueryDefinition qdef, Boolean filtered, long start, String afterUri, long pageLength, String forestName, R output) @@ -335,7 +307,7 @@ public boolean isExpected(int status) { R getGraphUris(RequestLogger reqlog, R output) throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException; - R readGraph(RequestLogger reqlog, String uri, R output, + void readGraph(RequestLogger reqlog, String uri, R output, Transaction transaction) throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException; void writeGraph(RequestLogger reqlog, String uri, @@ -343,7 +315,7 @@ void writeGraph(RequestLogger reqlog, String uri, throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException; void writeGraphs(RequestLogger reqlog, AbstractWriteHandle input, Transaction transaction) throws ResourceNotFoundException, ForbiddenUserException, FailedRequestException; - Object deleteGraph(RequestLogger requestLogger, String uri, + void deleteGraph(RequestLogger requestLogger, String uri, Transaction transaction) throws ForbiddenUserException, FailedRequestException; void deleteGraphs(RequestLogger requestLogger, Transaction transaction) diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/impl/okhttp/OkHttpUtil.java b/marklogic-client-api/src/main/java/com/marklogic/client/impl/okhttp/OkHttpUtil.java index 3dff7a53d..6a018cad2 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/impl/okhttp/OkHttpUtil.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/impl/okhttp/OkHttpUtil.java @@ -4,8 +4,10 @@ package com.marklogic.client.impl.okhttp; import com.marklogic.client.DatabaseClientFactory; +import com.marklogic.client.extra.okhttpclient.OkHttpClientConfigurator; import com.marklogic.client.impl.HTTPKerberosAuthInterceptor; import com.marklogic.client.impl.HTTPSamlAuthInterceptor; +import com.marklogic.client.impl.OkHttpServices; import com.marklogic.client.impl.SSLUtil; import okhttp3.*; @@ -21,6 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; /** @@ -35,7 +38,8 @@ public abstract class OkHttpUtil { final private static ConnectionPool connectionPool = new ConnectionPool(); @SuppressWarnings({"unchecked", "deprecation"}) - public static OkHttpClient.Builder newOkHttpClientBuilder(String host, DatabaseClientFactory.SecurityContext securityContext) { + public static OkHttpClient.Builder newOkHttpClientBuilder(String host, DatabaseClientFactory.SecurityContext securityContext, + List clientConfigurators) { OkHttpClient.Builder clientBuilder = OkHttpUtil.newClientBuilder(); AuthenticationConfigurer authenticationConfigurer = null; @@ -78,6 +82,10 @@ public static OkHttpClient.Builder newOkHttpClientBuilder(String host, DatabaseC OkHttpUtil.configureSocketFactory(clientBuilder, sslContext, trustManager); OkHttpUtil.configureHostnameVerifier(clientBuilder, sslVerifier); + if (clientConfigurators != null) { + clientConfigurators.forEach(configurator -> configurator.configure(clientBuilder)); + } + return clientBuilder; }