1818import com .marklogic .client .document .DocumentManager .Metadata ;
1919import com .marklogic .client .eval .EvalResult ;
2020import com .marklogic .client .eval .EvalResultIterator ;
21+ import com .marklogic .client .extra .okhttpclient .OkHttpClientConfigurator ;
2122import com .marklogic .client .impl .okhttp .HttpUrlBuilder ;
2223import com .marklogic .client .impl .okhttp .OkHttpUtil ;
2324import com .marklogic .client .impl .okhttp .PartIterator ;
@@ -74,10 +75,10 @@ public class OkHttpServices implements RESTServices {
7475
7576 static final private Logger logger = LoggerFactory .getLogger (OkHttpServices .class );
7677
77- static final public String OKHTTP_LOGGINGINTERCEPTOR_LEVEL = "com.marklogic.client.okhttp.httplogginginterceptor.level" ;
78- static final public String OKHTTP_LOGGINGINTERCEPTOR_OUTPUT = "com.marklogic.client.okhttp.httplogginginterceptor.output" ;
78+ private static final String OKHTTP_LOGGINGINTERCEPTOR_LEVEL = "com.marklogic.client.okhttp.httplogginginterceptor.level" ;
79+ private static final String OKHTTP_LOGGINGINTERCEPTOR_OUTPUT = "com.marklogic.client.okhttp.httplogginginterceptor.output" ;
7980
80- static final private String DOCUMENT_URI_PREFIX = "/documents?uri=" ;
81+ private static final String DOCUMENT_URI_PREFIX = "/documents?uri=" ;
8182
8283 static final private int DELAY_FLOOR = 125 ;
8384 static final private int DELAY_CEILING = 2000 ;
@@ -88,10 +89,14 @@ public class OkHttpServices implements RESTServices {
8889 private final static MediaType URLENCODED_MIME_TYPE = MediaType .parse ("application/x-www-form-urlencoded; charset=UTF-8" );
8990 private final static String UTF8_ID = StandardCharsets .UTF_8 .toString ();
9091
91- private DatabaseClient databaseClient ;
9292 private String database = null ;
9393 private HttpUrl baseUri ;
94- private OkHttpClient client ;
94+
95+ // This should really be final, but given the history of this class and the former "connect()" method that meant
96+ // the client was created in the constructor, this is being kept as non-final so it can be assigned a value of null
97+ // on release.
98+ private OkHttpClient okHttpClient ;
99+
95100 private boolean released = false ;
96101
97102 private final Random randRetry = new Random ();
@@ -114,25 +119,16 @@ static protected class ThreadState {
114119 private final ThreadLocal <ThreadState > threadState =
115120 ThreadLocal .withInitial (() -> new ThreadState (checkFirstRequest ));
116121
117- public OkHttpServices () {
122+ public record ConnectionConfig (String host , int port , String basePath , String database ,
123+ SecurityContext securityContext , List <OkHttpClientConfigurator > clientConfigurators ) {
124+ }
125+
126+ public OkHttpServices (ConnectionConfig connectionConfig ) {
118127 retryStatus .add (STATUS_BAD_GATEWAY );
119128 retryStatus .add (STATUS_SERVICE_UNAVAILABLE );
120129 retryStatus .add (STATUS_GATEWAY_TIMEOUT );
121- }
122130
123- @ Override
124- public Set <Integer > getRetryStatus () {
125- return retryStatus ;
126- }
127-
128- @ Override
129- public int getMaxDelay () {
130- return maxDelay ;
131- }
132-
133- @ Override
134- public void setMaxDelay (int maxDelay ) {
135- this .maxDelay = maxDelay ;
131+ this .okHttpClient = connect (connectionConfig );
136132 }
137133
138134 private FailedRequest extractErrorFields (Response response ) {
@@ -176,26 +172,27 @@ private FailedRequest extractErrorFields(Response response) {
176172 }
177173 }
178174
179- @ Override
180- public void connect (String host , int port , String basePath , String database , SecurityContext securityContext ) {
181- if (host == null )
175+ private OkHttpClient connect (ConnectionConfig config ) {
176+ if (config .host == null ) {
182177 throw new IllegalArgumentException ("No host provided" );
183- if (securityContext == null )
178+ }
179+ if (config .securityContext == null ) {
184180 throw new IllegalArgumentException ("No security context provided" );
181+ }
185182
186- this .checkFirstRequest = securityContext instanceof DigestAuthContext ;
187- this .database = database ;
188- this .baseUri = HttpUrlBuilder .newBaseUrl (host , port , basePath , securityContext .getSSLContext ());
183+ this .checkFirstRequest = config . securityContext instanceof DigestAuthContext ;
184+ this .database = config . database ;
185+ this .baseUri = HttpUrlBuilder .newBaseUrl (config . host , config . port , config . basePath , config . securityContext .getSSLContext ());
189186
190- OkHttpClient .Builder clientBuilder = OkHttpUtil .newOkHttpClientBuilder (host , securityContext );
187+ OkHttpClient .Builder clientBuilder = OkHttpUtil .newOkHttpClientBuilder (config . host , config . securityContext , config . clientConfigurators );
191188
192189 Properties props = System .getProperties ();
193190 if (props .containsKey (OKHTTP_LOGGINGINTERCEPTOR_LEVEL )) {
194191 configureOkHttpLogging (clientBuilder , props );
195192 }
196193 this .configureDelayAndRetry (props );
197194
198- this . client = clientBuilder .build ();
195+ return clientBuilder .build ();
199196 }
200197
201198 /**
@@ -244,40 +241,21 @@ private void configureDelayAndRetry(Properties props) {
244241 }
245242 }
246243
247- @ Override
248- public DatabaseClient getDatabaseClient () {
249- return databaseClient ;
250- }
251-
252- @ Override
253- public void setDatabaseClient (DatabaseClient client ) {
254- this .databaseClient = client ;
255- }
256-
257- private OkHttpClient getConnection () {
258- if (client != null ) {
259- return client ;
260- } else if (released ) {
261- throw new IllegalStateException (
262- "You cannot use this connected object anymore--connection has already been released" );
263- } else {
264- throw new MarkLogicInternalException ("Cannot proceed--connection is null for unknown reason" );
265- }
266- }
267-
268244 @ Override
269245 public void release () {
270- if (client == null ) return ;
246+ if (released || okHttpClient == null ) {
247+ return ;
248+ }
271249 try {
272250 released = true ;
273- client .dispatcher ().executorService ().shutdownNow ();
251+ okHttpClient .dispatcher ().executorService ().shutdownNow ();
274252 } finally {
275253 try {
276- if (client .cache () != null ) client .cache ().close ();
254+ if (okHttpClient .cache () != null ) okHttpClient .cache ().close ();
277255 } catch (IOException e ) {
278256 throw new MarkLogicIOException (e );
279257 } finally {
280- client = null ;
258+ okHttpClient = null ;
281259 logger .debug ("Releasing connection" );
282260 }
283261 }
@@ -491,8 +469,13 @@ private Response sendRequestOnce(Request.Builder requestBldr) {
491469 }
492470
493471 private Response sendRequestOnce (Request request ) {
472+ if (released ) {
473+ throw new IllegalStateException (
474+ "You cannot use this connected object anymore--connection has already been released" );
475+ }
476+
494477 try {
495- return getConnection () .newCall (request ).execute ();
478+ return okHttpClient .newCall (request ).execute ();
496479 } catch (IOException e ) {
497480 if (e instanceof SSLException ) {
498481 String message = e .getMessage ();
@@ -4843,12 +4826,7 @@ public <T> T getContentAs(Class<T> as) {
48434826
48444827 @ Override
48454828 public OkHttpClient getClientImplementation () {
4846- if (client == null ) return null ;
4847- return client ;
4848- }
4849-
4850- public void setClientImplementation (OkHttpClient client ) {
4851- this .client = client ;
4829+ return okHttpClient ;
48524830 }
48534831
48544832 @ Override
0 commit comments