001/*
002 * Copyright 2007-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2007-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2007-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk;
037
038
039
040import java.lang.reflect.Method;
041import java.net.InetAddress;
042import java.util.Arrays;
043import java.util.Collections;
044import java.util.EnumMap;
045import java.util.HashMap;
046import java.util.Map;
047import java.util.logging.Level;
048
049import com.unboundid.ldap.sdk.extensions.PasswordModifyExtendedRequest;
050import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
051import com.unboundid.ldap.sdk.extensions.WhoAmIExtendedRequest;
052import com.unboundid.ldap.sdk.unboundidds.extensions.
053            DeregisterYubiKeyOTPDeviceExtendedRequest;
054import com.unboundid.ldap.sdk.unboundidds.extensions.
055            EndAdministrativeSessionExtendedRequest;
056import com.unboundid.ldap.sdk.unboundidds.extensions.
057            GenerateTOTPSharedSecretExtendedRequest;
058import com.unboundid.ldap.sdk.unboundidds.extensions.
059            GetConnectionIDExtendedRequest;
060import com.unboundid.ldap.sdk.unboundidds.extensions.
061            GetPasswordQualityRequirementsExtendedRequest;
062import com.unboundid.ldap.sdk.unboundidds.extensions.
063            PasswordPolicyStateExtendedRequest;
064import com.unboundid.ldap.sdk.unboundidds.extensions.
065            RegisterYubiKeyOTPDeviceExtendedRequest;
066import com.unboundid.ldap.sdk.unboundidds.extensions.
067            RevokeTOTPSharedSecretExtendedRequest;
068import com.unboundid.ldap.sdk.unboundidds.extensions.
069            StartAdministrativeSessionExtendedRequest;
070import com.unboundid.ldap.sdk.unboundidds.extensions.
071            ValidateTOTPPasswordExtendedRequest;
072import com.unboundid.util.Debug;
073import com.unboundid.util.DebugType;
074import com.unboundid.util.Mutable;
075import com.unboundid.util.NotNull;
076import com.unboundid.util.Nullable;
077import com.unboundid.util.StaticUtils;
078import com.unboundid.util.ThreadSafety;
079import com.unboundid.util.ThreadSafetyLevel;
080import com.unboundid.util.Validator;
081import com.unboundid.util.ssl.HostNameSSLSocketVerifier;
082import com.unboundid.util.ssl.SSLSocketVerifier;
083import com.unboundid.util.ssl.TrustAllSSLSocketVerifier;
084
085
086
087/**
088 * This class provides a data structure that may be used to configure a number
089 * of connection-related properties.  Elements included in the set of connection
090 * options include:
091 * <UL>
092 *   <LI>A flag that indicates whether the SDK should attempt to automatically
093 *       re-establish a connection if it is unexpectedly closed.  By default,
094 *       it will not attempt to do so.</LI>
095 *   <LI>A flag that indicates whether simple bind attempts that contain a
096 *       non-empty DN will be required to have a non-empty password.  By
097 *       default, a password will be required in such cases.</LI>
098 *   <LI>A flag that indicates whether to automatically attempt to follow any
099 *       referrals that may be returned by the server.  By default, it will not
100 *       automatically attempt to follow referrals.</LI>
101 *   <LI>A referral hop limit, which indicates the maximum number of hops that
102 *       the connection may take when trying to follow a referral.  The default
103 *       referral hop limit is five.</LI>
104 *   <LI>The referral connector that should be used to create and optionally
105 *       authenticate connections used to follow referrals encountered during
106 *       processing.  By default, referral connections will use the same socket
107 *       factory and bind request as the client connection on which the referral
108 *       was received.</LI>
109 *   <LI>A flag that indicates whether to use the SO_KEEPALIVE socket option to
110 *       attempt to more quickly detect when idle TCP connections have been lost
111 *       or to prevent them from being unexpectedly closed by intermediate
112 *       network hardware.  By default, the SO_KEEPALIVE socket option will be
113 *       used.</LI>
114 *   <LI>A flag that indicates whether to use the SO_LINGER socket option to
115 *       indicate how long a connection should linger after it has been closed,
116 *       and a value that specifies the length of time that it should linger.
117 *       By default, the SO_LINGER option will be used with a timeout of 5
118 *       seconds.</LI>
119 *   <LI>A flag that indicates whether to use the SO_REUSEADDR socket option to
120 *       indicate that a socket in a TIME_WAIT state may be reused.  By default,
121 *       the SO_REUSEADDR socket option will be used.</LI>
122 *   <LI>A flag that indicates whether to operate in synchronous mode, in which
123 *       connections may exhibit better performance and will not require a
124 *       separate reader thread, but will not allow multiple concurrent
125 *       operations to be used on the same connection.</LI>
126 *   <LI>A flag that indicates whether to use the TCP_NODELAY socket option to
127 *       indicate that any data written to the socket will be sent immediately
128 *       rather than delaying for a short amount of time to see if any more data
129 *       is to be sent that could potentially be included in the same packet.
130 *       By default, the TCP_NODELAY socket option will be used.</LI>
131 *   <LI>A value that specifies the maximum length of time in milliseconds that
132 *       an attempt to establish a connection should be allowed to block before
133 *       failing.  By default, a timeout of 10,000 milliseconds (10 seconds)
134 *       will be used.</LI>
135 *   <LI>A value that specifies the default timeout in milliseconds that the SDK
136 *       should wait for a response from the server before failing.  This can be
137 *       defined on a per-operation-type basis, with a default of 300,000
138 *       milliseconds (5 minutes) for search and extended operations, and a
139 *       default timeout of 30,000 milliseconds (30 seconds) for all other types
140 *       of operations.  Further, the extended operation timeout can be
141 *       customized on a per-operation-type basis, and a number of extended
142 *       operation types have been configured with a 30,000 millisecond timeout
143 *       by default.  Individual requests can also be configured with their own
144 *       response timeouts, and if provided, that timeout will override the
145 *       default timeout from the connection options.</LI>
146 *   <LI>A flag that indicates whether to attempt to abandon any request for
147 *       which no response is received after waiting for the maximum response
148 *       timeout.  By default, no abandon request will be sent.</LI>
149 *   <LI>A value which specifies the largest LDAP message size that the SDK will
150 *       be willing to read from the directory server.  By default, the SDK will
151 *       not allow responses larger than 20,971,520 bytes (20MB).  If it
152 *       encounters a message that may be larger than the maximum allowed
153 *       message size, then the SDK will terminate the connection to the
154 *       server.</LI>
155 *   <LI>The {@link LDAPConnectionLogger} that should be used to record
156 *       information about requests sent and responses received over
157 *       connections with this set of options.  By default, no
158 *       {@code LDAPConnectionLogger} will be used.</LI>
159 *   <LI>The {@link DisconnectHandler} that should be used to receive
160 *       notification if connection is disconnected for any reason.  By default,
161 *       no {@code DisconnectHandler} will be used.</LI>
162 *   <LI>The {@link UnsolicitedNotificationHandler} that should be used to
163 *       receive notification about any unsolicited notifications returned by
164 *       the server.  By default, no {@code UnsolicitedNotificationHandler} will
165 *       be used.</LI>
166 *   <LI>A flag that indicates whether to capture a thread stack trace whenever
167 *       a new connection is established.  Capturing a thread stack trace when
168 *       establishing a connection may be marginally expensive, but can be
169 *       useful for debugging certain kinds of problems like leaked connections
170 *       (connections that are established but never explicitly closed).  By
171 *       default, connect stack traces will not be captured.</LI>
172 *   <LI>A flag that indicates whether connections should try to retrieve schema
173 *       information from the server, which may be used to better determine
174 *       which matching rules should be used when comparing attribute values.
175 *       By default, server schema information will not be retrieved.</LI>
176 *   <LI>The size of the socket receive buffer, which may be used for
177 *       temporarily holding data received from the directory server until it
178 *       can be read and processed by the LDAP SDK.  By default, the receive
179 *       buffer size will be automatically determined by the JVM based on the
180 *       underlying system settings.</LI>
181 *   <LI>The size of the socket send buffer, which may be used for temporarily
182 *       holding data to be sent to the directory server until it can actually
183 *       be transmitted over the network.  By default, the send buffer size will
184 *       be automatically determined by the JVM based on the underlying system
185 *       settings.</LI>
186 *  <LI>A flag which indicates whether to allow a single socket factory instance
187 *      (which may be shared across multiple connections) to be used to create
188 *      multiple concurrent connections.  This offers better and more
189 *      predictable performance on some JVM implementations (especially when
190 *      connection attempts fail as a result of a connection timeout), but some
191 *      JVMs are known to use non-threadsafe socket factory implementations and
192 *      may fail from concurrent use (for example, at least some IBM JVMs
193 *      exhibit this behavior).  By default, Sun/Oracle JVMs will allow
194 *      concurrent socket factory use, but JVMs from other vendors will use
195 *      synchronization to ensure that a socket factory will only be allowed to
196 *      create one connection at a time.</LI>
197 *  <LI>A class that may be used to perform additional verification (e.g.,
198 *      hostname validation) for any {@code SSLSocket} instances created.  By
199 *      default, no special verification will be performed.</LI>
200 * </UL>
201 */
202@Mutable()
203@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
204public final class LDAPConnectionOptions
205{
206  /**
207   * The prefix that will be used in conjunction with all system properties.
208   */
209  @NotNull private static final String PROPERTY_PREFIX =
210       LDAPConnectionOptions.class.getName() + '.';
211
212
213
214  /**
215   * The name of a system property that can be used to specify the initial
216   * default value for the "abandon on timeout" behavior.  If this property is
217   * set at the time that this class is loaded, then its value must be either
218   * "true" or "false".  If this property is not set, then a default value of
219   * "false" will be assumed.
220   * <BR><BR>
221   * The full name for this system property is
222   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultAbandonTimeout".
223   */
224  @NotNull public static final String PROPERTY_DEFAULT_ABANDON_ON_TIMEOUT =
225       PROPERTY_PREFIX + "defaultAbandonOnTimeout";
226
227
228
229  /**
230   * The default value for the setting that controls whether to automatically
231   * attempt to abandon any request for which no response is received within the
232   * maximum response timeout.  If the
233   * {@link #PROPERTY_DEFAULT_ABANDON_ON_TIMEOUT} system property is set at the
234   * time this class is loaded, then its value will be used.  Otherwise, a
235   * default of {@code false} will be used.
236   */
237  private static final boolean DEFAULT_ABANDON_ON_TIMEOUT =
238       getSystemProperty(PROPERTY_DEFAULT_ABANDON_ON_TIMEOUT, false);
239
240
241
242  /**
243   * The default value ({@code false}) for the setting that controls whether to
244   * automatically attempt to reconnect if a connection is unexpectedly lost.
245   */
246  private static final boolean DEFAULT_AUTO_RECONNECT = false;
247
248
249
250  /**
251   * The name of a system property that can be used to specify the initial
252   * default value for the "bind with DN requires password" behavior.  If this
253   * property is set at the time that this class is loaded, then its value must
254   * be either "true" or "false".  If this property is not set, then a default
255   * value of "true" will be assumed.
256   * <BR><BR>
257   * The full name for this system property is
258   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.
259   * defaultBindWithDNRequiresPassword".
260   */
261  @NotNull public static final String
262       PROPERTY_DEFAULT_BIND_WITH_DN_REQUIRES_PASSWORD =
263            PROPERTY_PREFIX + "defaultBindWithDNRequiresPassword";
264
265
266
267  /**
268   * The default value for the setting that controls whether simple bind
269   * requests with a DN will also be required to contain a password.  If the
270   * {@link #PROPERTY_DEFAULT_BIND_WITH_DN_REQUIRES_PASSWORD} system property is
271   * set at the time this class is loaded, then its value will be used.
272   * Otherwise, a default of {@code true} will be used.
273   */
274  private static final boolean DEFAULT_BIND_WITH_DN_REQUIRES_PASSWORD =
275       getSystemProperty(PROPERTY_DEFAULT_BIND_WITH_DN_REQUIRES_PASSWORD, true);
276
277
278
279  /**
280   * The name of a system property that can be used to specify the initial
281   * default value for the "capture connect stack trace" behavior.  If this
282   * property is set at the time that this class is loaded, then its value must
283   * be either "true" or "false".  If this property is not set, then a default
284   * value of "false" will be assumed.
285   * <BR><BR>
286   * The full name for this system property is "com.unboundid.ldap.sdk.
287   * LDAPConnectionOptions.defaultCaptureConnectStackTrace".
288   */
289  @NotNull public static final String
290       PROPERTY_DEFAULT_CAPTURE_CONNECT_STACK_TRACE =
291            PROPERTY_PREFIX + "defaultCaptureConnectStackTrace";
292
293
294
295  /**
296   * The default value for the setting that controls whether to capture a thread
297   * stack trace whenever an attempt is made to establish a connection.  If the
298   * {@link #PROPERTY_DEFAULT_CAPTURE_CONNECT_STACK_TRACE} system property is
299   * set at the time this class is loaded, then its value will be used.
300   * Otherwise, a default of {@code false} will be used.
301   */
302  private static final boolean DEFAULT_CAPTURE_CONNECT_STACK_TRACE =
303       getSystemProperty(PROPERTY_DEFAULT_CAPTURE_CONNECT_STACK_TRACE, false);
304
305
306
307  /**
308   * The name of a system property that can be used to specify the initial
309   * default value for the "follow referrals" behavior.  If this property is set
310   * at the time that this class is loaded, then its value must be either
311   * "true" or "false".  If this property is not set, then a default value of
312   * "false" will be assumed.
313   * <BR><BR>
314   * The full name for this system property is
315   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultFollowReferrals".
316   */
317  @NotNull public static final String PROPERTY_DEFAULT_FOLLOW_REFERRALS =
318       PROPERTY_PREFIX + "defaultFollowReferrals";
319
320
321
322  /**
323   * The default value for the setting that controls whether to attempt to
324   * automatically follow referrals.  If the
325   * {@link #PROPERTY_DEFAULT_FOLLOW_REFERRALS} system property is set at the
326   * time this class is loaded, then its value will be used.  Otherwise, a
327   * default of {@code false} will be used.
328   */
329  private static final boolean DEFAULT_FOLLOW_REFERRALS =
330       getSystemProperty(PROPERTY_DEFAULT_FOLLOW_REFERRALS, false);
331
332
333
334  /**
335   * The name of a system property that can be used to specify the maximum
336   * number of hops to make when following a referral.  If this property is set
337   * at the time that this class is loaded, then its value must be parseable as
338   * an integer.  If this property is not set, then a default value of "5" will
339   * be assumed.
340   * <BR><BR>
341   * The full name for this system property is
342   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultReferralHopLimit".
343   */
344  @NotNull public static final String PROPERTY_DEFAULT_REFERRAL_HOP_LIMIT =
345       PROPERTY_PREFIX + "defaultReferralHopLimit";
346
347
348
349  /**
350   * The default value for the setting that controls the referral hop limit.  If
351   * the {@link #PROPERTY_DEFAULT_REFERRAL_HOP_LIMIT} system property is set at
352   * the time this class is loaded, then its value will be used.  Otherwise, a
353   * default value of 5 will be used.
354   */
355  private static final int DEFAULT_REFERRAL_HOP_LIMIT =
356       getSystemProperty(PROPERTY_DEFAULT_REFERRAL_HOP_LIMIT, 5);
357
358
359
360  /**
361   * The name of a system property that can be used to specify the initial
362   * default value for the "use schema" behavior.  If this property is set at
363   * the time that this class is loaded, then its value must be either "true" or
364   * "false".  If this property is not set, then a default value of "false" will
365   * be assumed.
366   * <BR><BR>
367   * The full name for this system property is
368   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultUseSchema".
369   */
370  @NotNull public static final String PROPERTY_DEFAULT_USE_SCHEMA =
371       PROPERTY_PREFIX + "defaultUseSchema";
372
373
374
375  /**
376   * The default value for the setting that controls whether to use schema when
377   * reading data from the server.  If the {@link #PROPERTY_DEFAULT_USE_SCHEMA}
378   * system property is set at the time this class is loaded, then its value
379   * will be used.  Otherwise, a default value of {@code false} will be used.
380   */
381  private static final boolean DEFAULT_USE_SCHEMA =
382       getSystemProperty(PROPERTY_DEFAULT_USE_SCHEMA, false);
383
384
385
386  /**
387   * The name of a system property that can be used to specify the initial
388   * default value for the "use pooled schema" behavior.  If this property is
389   * set at the time that this class is loaded, then its value must be either
390   * "true" or "false".  If this property is not set, then a default value of
391   * "false" will be assumed.
392   * <BR><BR>
393   * The full name for this system property is
394   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultUsePooledSchema".
395   */
396  @NotNull public static final String PROPERTY_DEFAULT_USE_POOLED_SCHEMA =
397       PROPERTY_PREFIX + "defaultUsePooledSchema";
398
399
400
401  /**
402   * The default value for the setting that controls whether all connections in
403   * a connection pool should use the same cached schema object.  If the
404   * {@link #PROPERTY_DEFAULT_USE_POOLED_SCHEMA} system property is set at the
405   * time this class is loaded, then its value will be used.  Otherwise, a
406   * default of {@code false} will be used.
407   */
408  private static final boolean DEFAULT_USE_POOLED_SCHEMA =
409       getSystemProperty(PROPERTY_DEFAULT_USE_POOLED_SCHEMA, false);
410
411
412
413  /**
414   * The name of a system property that can be used to specify the initial
415   * default value for the pooled schema timeout, in milliseconds.  If this
416   * property is set at the time that this class is loaded, then its value must
417   * be parseable as an integer.  If this property is not set, then a default
418   * value of "3600000" (3,600,000 milliseconds, or 1 hour) will be assumed.
419   * <BR><BR>
420   * The full name for this system property is "com.unboundid.ldap.sdk.
421   * LDAPConnectionOptions.defaultPooledSchemaTimeoutMillis".
422   */
423  @NotNull public static final String
424       PROPERTY_DEFAULT_POOLED_SCHEMA_TIMEOUT_MILLIS =
425            PROPERTY_PREFIX + "defaultPooledSchemaTimeoutMillis";
426
427
428
429  /**
430   * The default value for the setting that controls the default pooled schema
431   * timeout.  If the {@link #PROPERTY_DEFAULT_POOLED_SCHEMA_TIMEOUT_MILLIS}
432   * system property is set at the time this class is loaded, then its value
433   * will be used.  Otherwise, a default of 3,600,000 milliseconds (1 hour) will
434   * be used.
435   */
436  private static final long DEFAULT_POOLED_SCHEMA_TIMEOUT_MILLIS = 3_600_000L;
437
438
439
440  /**
441   * The name of a system property that can be used to specify the initial
442   * default value for the "use keepalive" behavior.  If this property is set at
443   * the time that this class is loaded, then its value must be either "true" or
444   * "false".  If this property is not set, then a default value of "true" will
445   * be assumed.
446   * <BR><BR>
447   * The full name for this system property is
448   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultUseKeepalive".
449   */
450  @NotNull public static final String PROPERTY_DEFAULT_USE_KEEPALIVE =
451       PROPERTY_PREFIX + "defaultUseKeepalive";
452
453
454
455  /**
456   * The default value for the setting that controls whether to use the
457   * {@code SO_KEEPALIVE} socket option.  If the
458   * {@link #PROPERTY_DEFAULT_USE_KEEPALIVE} system property is set at the time
459   * this class is loaded, then its value will be used.  Otherwise, a default of
460   * {@code true} will be used.
461   */
462  private static final boolean DEFAULT_USE_KEEPALIVE =
463       getSystemProperty(PROPERTY_DEFAULT_USE_KEEPALIVE, true);
464
465
466
467  /**
468   * The name of a system property that can be used to specify the initial
469   * default value for the "use linger" behavior.  If this property is set at
470   * the time that this class is loaded, then its value must be either "true" or
471   * "false".  If this property is not set, then a default value of "true" will
472   * be assumed.
473   * <BR><BR>
474   * The full name for this system property is
475   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultUseLinger".
476   */
477  @NotNull public static final String PROPERTY_DEFAULT_USE_LINGER =
478       PROPERTY_PREFIX + "defaultUseLinger";
479
480
481
482  /**
483   * The default value for the setting that controls whether to use the
484   * {@code SO_LINGER} socket option.  If the
485   * {@link #PROPERTY_DEFAULT_USE_LINGER} system property is set at the time
486   * this class is loaded, then its value will be used.  Otherwise, a default of
487   * {@code true} will be used.
488   */
489  private static final boolean DEFAULT_USE_LINGER =
490       getSystemProperty(PROPERTY_DEFAULT_USE_LINGER, true);
491
492
493
494  /**
495   * The name of a system property that can be used to specify the initial
496   * default value for the linger timeout, in seconds.  If this property is set
497   * at the time that this class is loaded, then its value must be parseable as
498   * an integer.  If this property is not set, then a default value of "5" (5
499   * seconds) will be assumed.
500   * <BR><BR>
501   * The full name for this system property is
502   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultLingerTimeoutSeconds".
503   */
504  @NotNull public static final String PROPERTY_DEFAULT_LINGER_TIMEOUT_SECONDS =
505       PROPERTY_PREFIX + "defaultLingerTimeoutSeconds";
506
507
508
509  /**
510   * The default value for the setting that controls the timeout in seconds that
511   * will be used with the {@code SO_LINGER} socket option.  If the
512   * {@link #PROPERTY_DEFAULT_LINGER_TIMEOUT_SECONDS} property is set at the
513   * time this class is loaded, then its value will be used.  Otherwise, a
514   * default linger timeout of 5 seconds will be used.
515   */
516  private static final int DEFAULT_LINGER_TIMEOUT_SECONDS =
517       getSystemProperty(PROPERTY_DEFAULT_LINGER_TIMEOUT_SECONDS, 5);
518
519
520
521  /**
522   * The name of a system property that can be used to specify the initial
523   * default value for the "use reuse address" behavior.  If this property is
524   * set at the time that this class is loaded, then its value must be either
525   * "true" or "false".  If this property is not set, then a default value of
526   * "true" will be assumed.
527   * <BR><BR>
528   * The full name for this system property is
529   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultUseReuseAddress".
530   */
531  @NotNull public static final String PROPERTY_DEFAULT_USE_REUSE_ADDRESS =
532       PROPERTY_PREFIX + "defaultUseReuseAddress";
533
534
535
536  /**
537   * The default value for the setting that controls whether to use the
538   * {@code SO_REUSEADDR} socket option.  If the
539   * {@link #PROPERTY_DEFAULT_USE_REUSE_ADDRESS} system property is set at the
540   * time this class is loaded, then its value will be used.  Otherwise, a
541   * default value of {@code true} will be used.
542   */
543  private static final boolean DEFAULT_USE_REUSE_ADDRESS =
544       getSystemProperty(PROPERTY_DEFAULT_USE_REUSE_ADDRESS, true);
545
546
547
548  /**
549   * The name of a system property that can be used to specify the initial
550   * default value for the "use synchronous mode" behavior.  If this property is
551   * set at the time that this class is loaded, then its value must be either
552   * "true" or "false".  If this property is not set, then a default value of
553   * "false" will be assumed.
554   * <BR><BR>
555   * The full name for this system property is
556   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultUseSynchronousMode".
557   */
558  @NotNull public static final String PROPERTY_DEFAULT_USE_SYNCHRONOUS_MODE =
559       PROPERTY_PREFIX + "defaultUseSynchronousMode";
560
561
562
563  /**
564   * The default value for the setting that controls whether to operate in
565   * synchronous mode, in which only a single outstanding operation may be in
566   * progress on an associated connection at any given time.  If the
567   * {@link #PROPERTY_DEFAULT_USE_SYNCHRONOUS_MODE} system property is set at
568   * the time this class is loaded, then its value will be used.  Otherwise, a
569   * default value of {@code false} will be used.
570   */
571  private static final boolean DEFAULT_USE_SYNCHRONOUS_MODE =
572       getSystemProperty(PROPERTY_DEFAULT_USE_SYNCHRONOUS_MODE, false);
573
574
575
576  /**
577   * The name of a system property that can be used to specify the initial
578   * default value for the "use TCP nodelay" behavior.  If this property is set
579   * at the time that this class is loaded, then its value must be either "true"
580   * or "false".  If this property is not set, then a default value of "true"
581   * will be assumed.
582   * <BR><BR>
583   * The full name for this system property is
584   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultUseTCPNoDelay".
585   */
586  @NotNull public static final String PROPERTY_DEFAULT_USE_TCP_NODELAY =
587       PROPERTY_PREFIX + "defaultUseTCPNoDelay";
588
589
590
591  /**
592   * The default value for the setting that controls whether to use the
593   * {@code TCP_NODELAY} socket option.  If the
594   * {@link #PROPERTY_DEFAULT_USE_TCP_NODELAY} system property is set at the
595   * time this class is loaded, then its value will be used.  Otherwise, a
596   * default value of {@code true} will be used.
597   */
598  private static final boolean DEFAULT_USE_TCP_NODELAY =
599       getSystemProperty(PROPERTY_DEFAULT_USE_TCP_NODELAY, true);
600
601
602
603  /**
604   * The name of a system property that can be used to specify the initial
605   * default connect timeout, in milliseconds.  If this property is set at the
606   * time that this class is loaded, then its value must be parseable as an
607   * integer.  If this property is not set then a default value of "10000"
608   * (10,000 milliseconds, or ten seconds) will be assumed.
609   * <BR><BR>
610   * The full name for this system property is
611   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultConnectTimeoutMillis".
612   */
613  @NotNull public static final String PROPERTY_DEFAULT_CONNECT_TIMEOUT_MILLIS =
614       PROPERTY_PREFIX + "defaultConnectTimeoutMillis";
615
616
617
618  /**
619   * The default value for the setting that controls the timeout in milliseconds
620   * when trying to establish a new connection.  If the
621   * {@link #PROPERTY_DEFAULT_CONNECT_TIMEOUT_MILLIS} system property is set at
622   * the time this class is loaded, then its value will be used.  Otherwise, a
623   * default of 10,000 milliseconds (10 seconds) will be used.
624   */
625  private static final int DEFAULT_CONNECT_TIMEOUT_MILLIS =
626       getSystemProperty(PROPERTY_DEFAULT_CONNECT_TIMEOUT_MILLIS, 10_000);
627
628
629
630  /**
631   * The name of a system property that can be used to specify the initial
632   * default value for the maximum message size, in bytes.  If this property is
633   * set at the time that this class is loaded, then its value must be parseable
634   * as an integer.  If this property is not set, then a default value of
635   * "20971520" (20 megabytes) will be assumed.
636   * <BR><BR>
637   * The full name for this system property is
638   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultMaxMessageSizeBytes".
639   */
640  @NotNull public static final String PROPERTY_DEFAULT_MAX_MESSAGE_SIZE_BYTES =
641       PROPERTY_PREFIX + "defaultMaxMessageSizeBytes";
642
643
644
645  /**
646   * The default value for the setting that controls the maximum LDAP message
647   * size in bytes that will be allowed when reading data from a directory
648   * server.  If the {@link #PROPERTY_DEFAULT_MAX_MESSAGE_SIZE_BYTES} system
649   * property is set at the time this class is loaded, then its value will be
650   * used.  Otherwise, a default value of 20,971,520 bytes (20 megabytes) will
651   * be used.
652   */
653  private static final int DEFAULT_MAX_MESSAGE_SIZE_BYTES =
654       getSystemProperty(PROPERTY_DEFAULT_MAX_MESSAGE_SIZE_BYTES, 20_971_520);
655
656
657
658  /**
659   * The name of a system property that can be used to specify the initial
660   * default value for the receive buffer size, in bytes.  If this property is
661   * set at the time that this class is loaded, then its value must be parseable
662   * as an integer.  If this property is not set, then a default value of "0"
663   * (indicating that the JVM's default receive buffer size) will be assumed.
664   * <BR><BR>
665   * The full name for this system property is "com.unboundid.ldap.sdk.
666   * LDAPConnectionOptions.defaultReceiveBufferSizeBytes".
667   */
668  @NotNull public static final String
669       PROPERTY_DEFAULT_RECEIVE_BUFFER_SIZE_BYTES =
670            PROPERTY_PREFIX + "defaultReceiveBufferSizeBytes";
671
672
673
674  /**
675   * The default size, in bytes, to use for the receive buffer.  If the
676   * {@link #PROPERTY_DEFAULT_RECEIVE_BUFFER_SIZE_BYTES} system property is set
677   * at the time this class is loaded, then its value will be used.  Otherwise,
678   * a default value of 0 will be used to indicate that the JVM's default
679   * receive buffer size should be used.
680   */
681  private static final int DEFAULT_RECEIVE_BUFFER_SIZE_BYTES =
682       getSystemProperty(PROPERTY_DEFAULT_RECEIVE_BUFFER_SIZE_BYTES, 0);
683
684
685
686  /**
687   * The name of a system property that can be used to specify the initial
688   * default value for the send buffer size, in bytes.  If this property is set
689   * at the time that this class is loaded, then its value must be parseable as
690   * an integer.  If this property is not set, then a default value of "0"
691   * (indicating that the JVM's default send buffer size) will be assumed.
692   * <BR><BR>
693   * The full name for this system property is
694   * "com.unboundid.ldap.sdk.LDAPConnectionOptions.defaultSendBufferSizeBytes".
695   */
696  @NotNull public static final String PROPERTY_DEFAULT_SEND_BUFFER_SIZE_BYTES =
697       PROPERTY_PREFIX + "defaultSendBufferSizeBytes";
698
699
700
701  /**
702   * The default size, in bytes, to use for the send buffer.  If the
703   * {@link #PROPERTY_DEFAULT_SEND_BUFFER_SIZE_BYTES} system property is set at
704   * the time this class is loaded, then its value will be used.  Otherwise, a
705   * default value of 0 will be used to indicate that the JVM's default send
706   * buffer size should be used.
707   */
708  private static final int DEFAULT_SEND_BUFFER_SIZE_BYTES =
709       getSystemProperty(PROPERTY_DEFAULT_SEND_BUFFER_SIZE_BYTES, 0);
710
711
712
713  /**
714   * The name of a system property that can be used to specify the initial
715   * default value for response timeouts, in milliseconds, for all types of
716   * operations.  If this property is set at the time that this class is loaded,
717   * then its value must be parseable as an integer, and that value will
718   * override the values of any operation-specific properties.  If this property
719   * is not set, then a default value of "300000" (300,000 milliseconds, or
720   * 5 minutes) will be assumed, but that may be overridden by
721   * operation-specific properties.
722   * <BR><BR>
723   * The full name for this system property is "com.unboundid.ldap.sdk.
724   * LDAPConnectionOptions.defaultResponseTimeoutMillis".
725   */
726  @NotNull public static final String PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS =
727       PROPERTY_PREFIX + "defaultResponseTimeoutMillis";
728
729
730
731  /**
732   * The name of a system property that can be used to specify the initial
733   * default value for response timeouts, in milliseconds, for add operations.
734   * If this property is set at the time that this class is loaded, then
735   * its value must be parseable as an integer.  It will only be used if the
736   * {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} system property is not
737   * set, as that property will override this one.  If neither of those
738   * properties is set, then a default value of "30000" (30,000 milliseconds, or
739   * 30 seconds) will be assumed.
740   * <BR><BR>
741   * The full name for this system property is "com.unboundid.ldap.sdk.
742   * LDAPConnectionOptions.defaultAddResponseTimeoutMillis".
743   */
744  @NotNull public static final String
745       PROPERTY_DEFAULT_ADD_RESPONSE_TIMEOUT_MILLIS =
746            PROPERTY_PREFIX + "defaultAddResponseTimeoutMillis";
747
748
749
750  /**
751   * The name of a system property that can be used to specify the initial
752   * default value for response timeouts, in milliseconds, for bind operations.
753   * If this property is set at the time that this class is loaded, then
754   * its value must be parseable as an integer.  It will only be used if the
755   * {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} system property is not
756   * set, as that property will override this one.  If neither of those
757   * properties is set, then a default value of "30000" (30,000 milliseconds, or
758   * 30 seconds) will be assumed.
759   * <BR><BR>
760   * The full name for this system property is "com.unboundid.ldap.sdk.
761   * LDAPConnectionOptions.defaultBindResponseTimeoutMillis".
762   */
763  @NotNull public static final String
764       PROPERTY_DEFAULT_BIND_RESPONSE_TIMEOUT_MILLIS =
765            PROPERTY_PREFIX + "defaultBindResponseTimeoutMillis";
766
767
768
769  /**
770   * The name of a system property that can be used to specify the initial
771   * default value for response timeouts, in milliseconds, for compare
772   * operations.  If this property is set at the time that this class is
773   * loaded, then its value must be parseable as an integer.  It will only be
774   * used if the {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} system
775   * property is not set, as that property will override this one.  If neither
776   * of those properties is set, then a default value of "30000" (30,000
777   * milliseconds, or 30 seconds) will be assumed.
778   * <BR><BR>
779   * The full name for this system property is "com.unboundid.ldap.sdk.
780   * LDAPConnectionOptions.defaultCompareResponseTimeoutMillis".
781   */
782  @NotNull public static final String
783       PROPERTY_DEFAULT_COMPARE_RESPONSE_TIMEOUT_MILLIS =
784            PROPERTY_PREFIX + "defaultCompareResponseTimeoutMillis";
785
786
787
788  /**
789   * The name of a system property that can be used to specify the initial
790   * default value for response timeouts, in milliseconds, for delete
791   * operations.  If this property is set at the time that this class is
792   * loaded, then its value must be parseable as an integer.  It will only be
793   * used if the {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} system
794   * property is not set, as that property will override this one.  If neither
795   * of those properties is set, then a default value of "30000" (30,000
796   * milliseconds, or 30 seconds) will be assumed.
797   * <BR><BR>
798   * The full name for this system property is "com.unboundid.ldap.sdk.
799   * LDAPConnectionOptions.defaultDeleteResponseTimeoutMillis".
800   */
801  @NotNull public static final String
802       PROPERTY_DEFAULT_DELETE_RESPONSE_TIMEOUT_MILLIS =
803            PROPERTY_PREFIX + "defaultDeleteResponseTimeoutMillis";
804
805
806
807  /**
808   * The name of a system property that can be used to specify the initial
809   * default value for response timeouts, in milliseconds, for extended
810   * operations.  If this property is set at the time that this class is
811   * loaded, then its value must be parseable as an integer.  It will only be
812   * used if the {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} system
813   * property is not set, as that property will override this one.  If neither
814   * of those properties is set, then a default value of "300000" (300,000
815   * milliseconds, or 5 minutes) will be assumed.
816   * <BR><BR>
817   * The full name for this system property is "com.unboundid.ldap.sdk.
818   * LDAPConnectionOptions.defaultExtendedResponseTimeoutMillis".
819   * <BR><BR>
820   * Note that different timeouts may be set for specific types using a system
821   * property with this name immediately followed by a period and the request
822   * OID for the desired extended operation type.  For example, the system
823   * property named "com.unboundid.ldap.sdk.LDAPConnectionOptions.
824   * defaultExtendedResponseTimeoutMillis.1.3.6.1.4.1.1466.20037" can be used to
825   * set a default response timeout for StartTLS extended operations.
826   * <BR><BR>
827   * If neither the {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} nor the
828   * {@code PROPERTY_DEFAULT_EXTENDED_RESPONSE_TIMEOUT_MILLIS} property is set,
829   * then the following standard extended operation types will have a default
830   * timeout of 30,000 milliseconds (30 seconds) instead of 300,000 milliseconds
831   * (5 minutes), unless a property is defined to override the timeout for that
832   * specific type of extended operation:
833   * <BR>
834   * <UL>
835   *   <LI>Password Modify (1.3.6.1.4.1.4203.1.11.1)</LI>
836   *   <LI>StartTLS (1.3.6.1.4.1.1466.20037)</LI>
837   *   <LI>Who Am I? (1.3.6.1.4.1.4203.1.11.3)</LI>
838   * </UL>
839   * <BR>
840   * The same will also be true for the following extended operations specific
841   * to the UnboundID/Ping Identity Directory Server:
842   * <BR>
843   * <UL>
844   *   <LI>Deregister YubiKey OTP Device (1.3.6.1.4.1.30221.2.6.55)</LI>
845   *   <LI>End Administrative Session (1.3.6.1.4.1.30221.2.6.14)</LI>
846   *   <LI>Generate TOTP Shared Secret (1.3.6.1.4.1.30221.2.6.56)</LI>
847   *   <LI>Get Connection ID (1.3.6.1.4.1.30221.1.6.2)</LI>
848   *   <LI>Get Password Quality Requirements (1.3.6.1.4.1.30221.2.6.43)</LI>
849   *   <LI>Password Policy State (1.3.6.1.4.1.30221.1.6.1)</LI>
850   *   <LI>Register YubiKey OTP Device (1.3.6.1.4.1.30221.2.6.54)</LI>
851   *   <LI>Revoke TOTP Shared Secret (1.3.6.1.4.1.30221.2.6.58)</LI>
852   *   <LI>Start Administrative Session (1.3.6.1.4.1.30221.2.6.13)</LI>
853   *   <LI>Validate TOTP Password (1.3.6.1.4.1.30221.2.6.15)</LI>
854   * </UL>
855   */
856  @NotNull public static final String
857       PROPERTY_DEFAULT_EXTENDED_RESPONSE_TIMEOUT_MILLIS =
858            PROPERTY_PREFIX + "defaultExtendedResponseTimeoutMillis";
859
860
861
862  /**
863   * The name of a system property that can be used to specify the initial
864   * default value for response timeouts, in milliseconds, for modify
865   * operations.  If this property is set at the time that this class is
866   * loaded, then its value must be parseable as an integer.  It will only be
867   * used if the {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} system
868   * property is not set, as that property will override this one.  If neither
869   * of those properties is set, then a default value of "30000" (30,000
870   * milliseconds, or 30 seconds) will be assumed.
871   * <BR><BR>
872   * The full name for this system property is "com.unboundid.ldap.sdk.
873   * LDAPConnectionOptions.defaultModifyResponseTimeoutMillis".
874   */
875  @NotNull public static final String
876       PROPERTY_DEFAULT_MODIFY_RESPONSE_TIMEOUT_MILLIS =
877            PROPERTY_PREFIX + "defaultModifyResponseTimeoutMillis";
878
879
880
881  /**
882   * The name of a system property that can be used to specify the initial
883   * default value for response timeouts, in milliseconds, for modify DN
884   * operations.  If this property is set at the time that this class is
885   * loaded, then its value must be parseable as an integer.  It will only be
886   * used if the {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} system
887   * property is not set, as that property will override this one.  If neither
888   * of those properties is set, then a default value of "30000" (30,000
889   * milliseconds, or 30 seconds) will be assumed.
890   * <BR><BR>
891   * The full name for this system property is "com.unboundid.ldap.sdk.
892   * LDAPConnectionOptions.defaultModifyDNResponseTimeoutMillis".
893   */
894  @NotNull public static final String
895       PROPERTY_DEFAULT_MODIFY_DN_RESPONSE_TIMEOUT_MILLIS =
896            PROPERTY_PREFIX + "defaultModifyDNResponseTimeoutMillis";
897
898
899
900  /**
901   * The name of a system property that can be used to specify the initial
902   * default value for response timeouts, in milliseconds, for search
903   * operations.  If this property is set at the time that this class is
904   * loaded, then its value must be parseable as an integer.  It will only be
905   * used if the {@link #PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS} system
906   * property is not set, as that property will override this one.  If neither
907   * of those properties is set, then a default value of "300000" (300,000
908   * milliseconds, or 5 minutes) will be assumed.
909   * <BR><BR>
910   * The full name for this system property is "com.unboundid.ldap.sdk.
911   * LDAPConnectionOptions.defaultSearchResponseTimeoutMillis".
912   */
913  @NotNull public static final String
914       PROPERTY_DEFAULT_SEARCH_RESPONSE_TIMEOUT_MILLIS =
915            PROPERTY_PREFIX + "defaultSearchResponseTimeoutMillis";
916
917
918
919  /**
920   * The default value for the setting that controls the default response
921   * timeout, in milliseconds, for all types of operations.
922   */
923  private static final long DEFAULT_RESPONSE_TIMEOUT_MILLIS;
924
925
926
927  /**
928   * A map that holds the default values for the settings that control the
929   * default response timeouts, in milliseconds, for each type of operation.
930   */
931  @NotNull private static final Map<OperationType,Long>
932       DEFAULT_RESPONSE_TIMEOUT_MILLIS_BY_OPERATION_TYPE;
933
934
935
936  /**
937   * A map that holds the default values for the settings that control the
938   * default response timeouts, in milliseconds, for specific types of extended
939   * operations.
940   */
941  @NotNull private static final Map<String,Long>
942       DEFAULT_RESPONSE_TIMEOUT_MILLIS_BY_EXTENDED_OPERATION_TYPE;
943
944
945
946  /**
947   * The default name resolver that will be used to resolve host names to IP
948   * addresses.
949   */
950  @NotNull public static final NameResolver DEFAULT_NAME_RESOLVER;
951
952
953
954  static
955  {
956    // Get the default response timeout for all types of operations.
957    Long allOpsTimeout = null;
958    final EnumMap<OperationType,Long> timeoutsByOpType =
959         new EnumMap<>(OperationType.class);
960    final HashMap<String,Long> timeoutsByExtOpType =
961         new HashMap<>(StaticUtils.computeMapCapacity(10));
962
963    final String allOpsPropertyValue = StaticUtils.getSystemProperty(
964         PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS);
965    if (allOpsPropertyValue != null)
966    {
967      try
968      {
969        allOpsTimeout = Math.max(0L, Long.parseLong(allOpsPropertyValue));
970        for (final OperationType ot : OperationType.values())
971        {
972          timeoutsByOpType.put(ot, allOpsTimeout);
973        }
974
975        if (Debug.debugEnabled())
976        {
977          Debug.debug(Level.INFO, DebugType.OTHER,
978               "Using value " + allOpsTimeout + " set for system property '" +
979                  PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS + "'.  This " +
980                    "timeout will be used for all operation types.");
981        }
982      }
983      catch (final Exception e)
984      {
985        if (Debug.debugEnabled())
986        {
987          Debug.debugException(e);
988          Debug.debug(Level.WARNING, DebugType.OTHER,
989               "Invalid value '" + allOpsPropertyValue + "' set for system " +
990                    "property '" + PROPERTY_DEFAULT_RESPONSE_TIMEOUT_MILLIS +
991                    "'.  The value was expected to be a long.  Ignoring " +
992                    "this property and proceeding as if it had not been set.");
993        }
994      }
995    }
996
997
998    // Get the default response timeout for each type of operation.
999    if (allOpsTimeout == null)
1000    {
1001      allOpsTimeout = 300_000L;
1002
1003      // Use hard-coded response timeouts of 10 seconds for abandon and unbind
1004      // operations.  There is no response for these operations, but the timeout
1005      // is also used for sending the request.
1006      timeoutsByOpType.put(OperationType.ABANDON, 10_000L);
1007      timeoutsByOpType.put(OperationType.UNBIND, 10_000L);
1008
1009      timeoutsByOpType.put(OperationType.ADD,
1010           getSystemProperty(PROPERTY_DEFAULT_ADD_RESPONSE_TIMEOUT_MILLIS,
1011                30_000L));
1012      timeoutsByOpType.put(OperationType.BIND,
1013           getSystemProperty(PROPERTY_DEFAULT_BIND_RESPONSE_TIMEOUT_MILLIS,
1014                30_000L));
1015      timeoutsByOpType.put(OperationType.COMPARE,
1016           getSystemProperty(PROPERTY_DEFAULT_COMPARE_RESPONSE_TIMEOUT_MILLIS,
1017                30_000L));
1018      timeoutsByOpType.put(OperationType.DELETE,
1019           getSystemProperty(PROPERTY_DEFAULT_DELETE_RESPONSE_TIMEOUT_MILLIS,
1020                30_000L));
1021      timeoutsByOpType.put(OperationType.MODIFY,
1022           getSystemProperty(PROPERTY_DEFAULT_MODIFY_RESPONSE_TIMEOUT_MILLIS,
1023                30_000L));
1024      timeoutsByOpType.put(OperationType.MODIFY_DN,
1025           getSystemProperty(PROPERTY_DEFAULT_MODIFY_DN_RESPONSE_TIMEOUT_MILLIS,
1026                30_000L));
1027      timeoutsByOpType.put(OperationType.SEARCH,
1028           getSystemProperty(PROPERTY_DEFAULT_SEARCH_RESPONSE_TIMEOUT_MILLIS,
1029                300_000L));
1030
1031      final String extendedOperationTypePrefix =
1032           PROPERTY_DEFAULT_EXTENDED_RESPONSE_TIMEOUT_MILLIS + '.';
1033      for (final String propertyName :
1034           StaticUtils.getSystemProperties().stringPropertyNames())
1035      {
1036        if (propertyName.startsWith(extendedOperationTypePrefix))
1037        {
1038          final Long value = getSystemProperty(propertyName, null);
1039          if (value != null)
1040          {
1041            final String oid = propertyName.substring(
1042                 extendedOperationTypePrefix.length());
1043            timeoutsByExtOpType.put(oid, value);
1044          }
1045        }
1046      }
1047
1048
1049      // Get the default response timeout for different types of extended
1050      // operations.
1051      final Long extendedOpTimeout = getSystemProperty(
1052           PROPERTY_DEFAULT_EXTENDED_RESPONSE_TIMEOUT_MILLIS, null);
1053      if (extendedOpTimeout == null)
1054      {
1055        timeoutsByOpType.put(OperationType.EXTENDED, 300_000L);
1056
1057        for (final String oid :
1058          Arrays.asList(
1059               PasswordModifyExtendedRequest.PASSWORD_MODIFY_REQUEST_OID,
1060               StartTLSExtendedRequest.STARTTLS_REQUEST_OID,
1061               WhoAmIExtendedRequest.WHO_AM_I_REQUEST_OID,
1062               DeregisterYubiKeyOTPDeviceExtendedRequest.
1063                    DEREGISTER_YUBIKEY_OTP_DEVICE_REQUEST_OID,
1064               EndAdministrativeSessionExtendedRequest.
1065                    END_ADMIN_SESSION_REQUEST_OID,
1066               GenerateTOTPSharedSecretExtendedRequest.
1067                    GENERATE_TOTP_SHARED_SECRET_REQUEST_OID,
1068               GetConnectionIDExtendedRequest.GET_CONNECTION_ID_REQUEST_OID,
1069               GetPasswordQualityRequirementsExtendedRequest.
1070                    OID_GET_PASSWORD_QUALITY_REQUIREMENTS_REQUEST,
1071               PasswordPolicyStateExtendedRequest.
1072                    PASSWORD_POLICY_STATE_REQUEST_OID,
1073               RegisterYubiKeyOTPDeviceExtendedRequest.
1074                    REGISTER_YUBIKEY_OTP_DEVICE_REQUEST_OID,
1075               RevokeTOTPSharedSecretExtendedRequest.
1076                    REVOKE_TOTP_SHARED_SECRET_REQUEST_OID,
1077               StartAdministrativeSessionExtendedRequest.
1078                    START_ADMIN_SESSION_REQUEST_OID,
1079               ValidateTOTPPasswordExtendedRequest.
1080                    VALIDATE_TOTP_PASSWORD_REQUEST_OID))
1081        {
1082          if (! timeoutsByExtOpType.containsKey(oid))
1083          {
1084            timeoutsByExtOpType.put(oid, 30_000L);
1085          }
1086        }
1087      }
1088      else
1089      {
1090        timeoutsByOpType.put(OperationType.EXTENDED, extendedOpTimeout);
1091      }
1092    }
1093
1094
1095    // Get the default name resolver to use.  If the LDAP SDK is running with
1096    // access to the Ping Identity Directory Server's codebase, then we'll use
1097    // the server's default name resolver instead of the LDAP SDK's.
1098    NameResolver defaultNameResolver = DefaultNameResolver.getInstance();
1099    try
1100    {
1101      if (InternalSDKHelper.getPingIdentityServerRoot() != null)
1102      {
1103        final Class<?> nrClass = Class.forName(
1104             "com.unboundid.directory.server.util.OutageSafeDnsCache");
1105        final Method getNameResolverMethod =
1106             nrClass.getMethod("getNameResolver");
1107        final NameResolver nameResolver =
1108             (NameResolver) getNameResolverMethod.invoke(null);
1109
1110        final InetAddress localHostAddress = nameResolver.getLocalHost();
1111        if (localHostAddress != null)
1112        {
1113          if (nameResolver.getByName(localHostAddress.getHostAddress()) != null)
1114          {
1115            defaultNameResolver = nameResolver;
1116          }
1117        }
1118      }
1119    }
1120    catch (final Throwable t)
1121    {
1122      // This is probably fine.  It just means that we're not running with
1123      // access to the server codebase (or a version of the server codebase that
1124      // supports the LDAP SDK's name resolver API), or without the appropriate
1125      // setup in place (e.g., knowledge of the server root).  In this case,
1126      // we'll just use the LDAP SDK's default resolver.
1127      //
1128      // Note that we intentionally catch Throwable in this case rather than
1129      // just Exception because even if the server code is available, there
1130      // may be an unexpected Error thrown (e.g., NoClassDefFound or
1131      // ExceptionInInitializerError) under certain circumstances, like if the
1132      // server's name resolver code cannot identify the server root.
1133      Debug.debugException(Level.FINEST, t);
1134    }
1135
1136
1137    DEFAULT_RESPONSE_TIMEOUT_MILLIS = allOpsTimeout;
1138    DEFAULT_RESPONSE_TIMEOUT_MILLIS_BY_OPERATION_TYPE =
1139         Collections.unmodifiableMap(timeoutsByOpType);
1140    DEFAULT_RESPONSE_TIMEOUT_MILLIS_BY_EXTENDED_OPERATION_TYPE =
1141         Collections.unmodifiableMap(timeoutsByExtOpType);
1142    DEFAULT_NAME_RESOLVER = defaultNameResolver;
1143  }
1144
1145
1146
1147  /**
1148   * The name of a system property that can be used to specify the default value
1149   * for the "allow concurrent socket factory use" behavior.  If this property
1150   * is set at the time that this class is loaded, then its value must be
1151   * either "true" or "false".  If this property is not set, then a default
1152   * value of "true" will be assumed.
1153   * <BR><BR>
1154   * The full name for this system property is "com.unboundid.ldap.sdk.
1155   * LDAPConnectionOptions.defaultAllowConcurrentSocketFactoryUse".
1156   */
1157  @NotNull public static final String
1158       PROPERTY_DEFAULT_ALLOW_CONCURRENT_SOCKET_FACTORY_USE =
1159            PROPERTY_PREFIX + "defaultAllowConcurrentSocketFactoryUse";
1160
1161
1162
1163  /**
1164   * The default value for the setting that controls the default behavior with
1165   * regard to whether to allow concurrent use of a socket factory to create
1166   * client connections.
1167   */
1168  private static final boolean DEFAULT_ALLOW_CONCURRENT_SOCKET_FACTORY_USE =
1169       getSystemProperty(PROPERTY_DEFAULT_ALLOW_CONCURRENT_SOCKET_FACTORY_USE,
1170            true);
1171
1172
1173
1174  /**
1175   * The name of a system property that can be used to indicate that the LDAP
1176   * SDK should perform validation for certificate hostnames when negotiating a
1177   * TLS session.  By default, this validation will only be enabled if the
1178   * {@link #setSSLSocketVerifier} method is called and provided with an
1179   * {@link HostNameSSLSocketVerifier} instance.  However, if this property is
1180   * set with a value of "true", then connections will use a
1181   * {@code HostNameSSLSocketVerifier} by default, and attempts to establish a
1182   * secure connection will fail if the address used to establish the connection
1183   * does not match any of the allowed addresses for that certificate (e.g., in
1184   * its subject alternative name extension).
1185   * <BR><BR>
1186   * The full name for this system property is "com.unboundid.ldap.sdk.
1187   * LDAPConnectionOptions.defaultVerifyCertificateHostnames".
1188   */
1189  @NotNull public static final String
1190       PROPERTY_DEFAULT_VERIFY_CERTIFICATE_HOSTNAMES =
1191            PROPERTY_PREFIX + "defaultVerifyCertificateHostnames";
1192
1193
1194
1195  /**
1196   * The default {@code SSLSocketVerifier} instance that will be used for
1197   * performing extra validation for {@code SSLSocket} instances.
1198   */
1199  @NotNull private static final SSLSocketVerifier DEFAULT_SSL_SOCKET_VERIFIER =
1200       getSystemProperty(PROPERTY_DEFAULT_VERIFY_CERTIFICATE_HOSTNAMES, false)
1201            ? new HostNameSSLSocketVerifier(true)
1202            : TrustAllSSLSocketVerifier.getInstance();
1203
1204
1205
1206  // Indicates whether to send an abandon request for any operation for which no
1207  // response is received in the maximum response timeout.
1208  private boolean abandonOnTimeout;
1209
1210  // Indicates whether to use synchronization prevent concurrent use of the
1211  // socket factory instance associated with a connection or set of connections.
1212  private boolean allowConcurrentSocketFactoryUse;
1213
1214  // Indicates whether the connection should attempt to automatically reconnect
1215  // if the connection to the server is lost.
1216  private boolean autoReconnect;
1217
1218  // Indicates whether to allow simple binds that contain a DN but no password.
1219  private boolean bindWithDNRequiresPassword;
1220
1221  // Indicates whether to capture a thread stack trace whenever an attempt is
1222  // made to establish a connection;
1223  private boolean captureConnectStackTrace;
1224
1225  // Indicates whether to attempt to follow any referrals that are encountered.
1226  private boolean followReferrals;
1227
1228  // Indicates whether to use SO_KEEPALIVE for the underlying sockets.
1229  private boolean useKeepAlive;
1230
1231  // Indicates whether to use SO_LINGER for the underlying sockets.
1232  private boolean useLinger;
1233
1234  // Indicates whether to use SO_REUSEADDR for the underlying sockets.
1235  private boolean useReuseAddress;
1236
1237  // Indicates whether all connections in a connection pool should reference
1238  // the same schema.
1239  private boolean usePooledSchema;
1240
1241  // Indicates whether to try to use schema information when reading data from
1242  // the server.
1243  private boolean useSchema;
1244
1245  // Indicates whether to use synchronous mode in which only a single operation
1246  // may be in progress on associated connections at any given time.
1247  private boolean useSynchronousMode;
1248
1249  // Indicates whether to use TCP_NODELAY for the underlying sockets.
1250  private boolean useTCPNoDelay;
1251
1252  // The disconnect handler for associated connections.
1253  @Nullable private DisconnectHandler disconnectHandler;
1254
1255  // The connect timeout, in milliseconds.
1256  private int connectTimeoutMillis;
1257
1258  // The linger timeout to use if SO_LINGER is to be used.
1259  private int lingerTimeoutSeconds;
1260
1261  // The maximum message size in bytes that will be allowed when reading data
1262  // from a directory server.
1263  private int maxMessageSizeBytes;
1264
1265  // The socket receive buffer size to request.
1266  private int receiveBufferSizeBytes;
1267
1268  // The referral hop limit to use if referral following is enabled.
1269  private int referralHopLimit;
1270
1271  // The socket send buffer size to request.
1272  private int sendBufferSizeBytes;
1273
1274  // The connection logger that should be used to record information about
1275  // requests sent and responses received over connections with this set of
1276  // options.
1277  @Nullable private LDAPConnectionLogger connectionLogger;
1278
1279  // The pooled schema timeout, in milliseconds.
1280  private long pooledSchemaTimeoutMillis;
1281
1282  // The response timeout, in milliseconds.
1283  private long responseTimeoutMillis;
1284
1285  @NotNull private Map<OperationType,Long> responseTimeoutMillisByOperationType;
1286
1287  @NotNull private Map<String,Long>
1288       responseTimeoutMillisByExtendedOperationType;
1289
1290  // The name resolver that will be used to resolve host names to IP addresses.
1291  @NotNull private NameResolver nameResolver;
1292
1293  // Tne default referral connector that should be used for associated
1294  // connections.
1295  @Nullable private ReferralConnector referralConnector;
1296
1297  // The SSLSocketVerifier instance to use to perform extra validation on
1298  // newly-established SSLSocket instances.
1299  @NotNull private SSLSocketVerifier sslSocketVerifier;
1300
1301  // The unsolicited notification handler for associated connections.
1302  @Nullable private UnsolicitedNotificationHandler
1303       unsolicitedNotificationHandler;
1304
1305
1306
1307  /**
1308   * Creates a new set of LDAP connection options with the default settings.
1309   */
1310  public LDAPConnectionOptions()
1311  {
1312    abandonOnTimeout               = DEFAULT_ABANDON_ON_TIMEOUT;
1313    autoReconnect                  = DEFAULT_AUTO_RECONNECT;
1314    bindWithDNRequiresPassword     = DEFAULT_BIND_WITH_DN_REQUIRES_PASSWORD;
1315    captureConnectStackTrace       = DEFAULT_CAPTURE_CONNECT_STACK_TRACE;
1316    followReferrals                = DEFAULT_FOLLOW_REFERRALS;
1317    nameResolver                   = DEFAULT_NAME_RESOLVER;
1318    useKeepAlive                   = DEFAULT_USE_KEEPALIVE;
1319    useLinger                      = DEFAULT_USE_LINGER;
1320    useReuseAddress                = DEFAULT_USE_REUSE_ADDRESS;
1321    usePooledSchema                = DEFAULT_USE_POOLED_SCHEMA;
1322    useSchema                      = DEFAULT_USE_SCHEMA;
1323    useSynchronousMode             = DEFAULT_USE_SYNCHRONOUS_MODE;
1324    useTCPNoDelay                  = DEFAULT_USE_TCP_NODELAY;
1325    connectTimeoutMillis           = DEFAULT_CONNECT_TIMEOUT_MILLIS;
1326    lingerTimeoutSeconds           = DEFAULT_LINGER_TIMEOUT_SECONDS;
1327    maxMessageSizeBytes            = DEFAULT_MAX_MESSAGE_SIZE_BYTES;
1328    referralHopLimit               = DEFAULT_REFERRAL_HOP_LIMIT;
1329    pooledSchemaTimeoutMillis      = DEFAULT_POOLED_SCHEMA_TIMEOUT_MILLIS;
1330    responseTimeoutMillis          = DEFAULT_RESPONSE_TIMEOUT_MILLIS;
1331    receiveBufferSizeBytes         = DEFAULT_RECEIVE_BUFFER_SIZE_BYTES;
1332    sendBufferSizeBytes            = DEFAULT_SEND_BUFFER_SIZE_BYTES;
1333    connectionLogger               = null;
1334    disconnectHandler              = null;
1335    referralConnector              = null;
1336    sslSocketVerifier              = DEFAULT_SSL_SOCKET_VERIFIER;
1337    unsolicitedNotificationHandler = null;
1338
1339    responseTimeoutMillisByOperationType =
1340         DEFAULT_RESPONSE_TIMEOUT_MILLIS_BY_OPERATION_TYPE;
1341    responseTimeoutMillisByExtendedOperationType =
1342         DEFAULT_RESPONSE_TIMEOUT_MILLIS_BY_EXTENDED_OPERATION_TYPE;
1343    allowConcurrentSocketFactoryUse =
1344         DEFAULT_ALLOW_CONCURRENT_SOCKET_FACTORY_USE;
1345  }
1346
1347
1348
1349  /**
1350   * Returns a duplicate of this LDAP connection options object that may be
1351   * modified without impacting this instance.
1352   *
1353   * @return  A duplicate of this LDAP connection options object that may be
1354   *          modified without impacting this instance.
1355   */
1356  @NotNull()
1357  public LDAPConnectionOptions duplicate()
1358  {
1359    final LDAPConnectionOptions o = new LDAPConnectionOptions();
1360
1361    o.abandonOnTimeout                = abandonOnTimeout;
1362    o.allowConcurrentSocketFactoryUse = allowConcurrentSocketFactoryUse;
1363    o.autoReconnect                   = autoReconnect;
1364    o.bindWithDNRequiresPassword      = bindWithDNRequiresPassword;
1365    o.captureConnectStackTrace        = captureConnectStackTrace;
1366    o.followReferrals                 = followReferrals;
1367    o.nameResolver                    = nameResolver;
1368    o.useKeepAlive                    = useKeepAlive;
1369    o.useLinger                       = useLinger;
1370    o.useReuseAddress                 = useReuseAddress;
1371    o.usePooledSchema                 = usePooledSchema;
1372    o.useSchema                       = useSchema;
1373    o.useSynchronousMode              = useSynchronousMode;
1374    o.useTCPNoDelay                   = useTCPNoDelay;
1375    o.connectTimeoutMillis            = connectTimeoutMillis;
1376    o.lingerTimeoutSeconds            = lingerTimeoutSeconds;
1377    o.maxMessageSizeBytes             = maxMessageSizeBytes;
1378    o.pooledSchemaTimeoutMillis       = pooledSchemaTimeoutMillis;
1379    o.responseTimeoutMillis           = responseTimeoutMillis;
1380    o.referralConnector               = referralConnector;
1381    o.referralHopLimit                = referralHopLimit;
1382    o.connectionLogger                = connectionLogger;
1383    o.disconnectHandler               = disconnectHandler;
1384    o.unsolicitedNotificationHandler  = unsolicitedNotificationHandler;
1385    o.receiveBufferSizeBytes          = receiveBufferSizeBytes;
1386    o.sendBufferSizeBytes             = sendBufferSizeBytes;
1387    o.sslSocketVerifier               = sslSocketVerifier;
1388
1389    o.responseTimeoutMillisByOperationType =
1390         responseTimeoutMillisByOperationType;
1391    o.responseTimeoutMillisByExtendedOperationType =
1392         responseTimeoutMillisByExtendedOperationType;
1393
1394    return o;
1395  }
1396
1397
1398
1399  /**
1400   * Indicates whether associated connections should attempt to automatically
1401   * reconnect to the target server if the connection is lost.  Note that this
1402   * option will not have any effect on pooled connections because defunct
1403   * pooled connections will be replaced by newly-created connections rather
1404   * than attempting to re-establish the existing connection.
1405   * <BR><BR>
1406   * NOTE:  The use of auto-reconnect is strongly discouraged because it is
1407   * inherently fragile and can only work under very limited circumstances.  It
1408   * is strongly recommended that a connection pool be used instead of the
1409   * auto-reconnect option, even in cases where only a single connection is
1410   * desired.
1411   *
1412   * @return  {@code true} if associated connections should attempt to
1413   *          automatically reconnect to the target server if the connection is
1414   *          lost, or {@code false} if not.
1415   *
1416   * @deprecated  The use of auto-reconnect is strongly discouraged because it
1417   *              is inherently fragile and can only work under very limited
1418   *              circumstances.  It is strongly recommended that a connection
1419   *              pool be used instead of the auto-reconnect option, even in
1420   *              cases where only a single connection is desired.
1421   */
1422  @Deprecated()
1423  public boolean autoReconnect()
1424  {
1425    return autoReconnect;
1426  }
1427
1428
1429
1430  /**
1431   * Specifies whether associated connections should attempt to automatically
1432   * reconnect to the target server if the connection is lost.  Note that
1433   * automatic reconnection will only be available for authenticated clients if
1434   * the authentication mechanism used provides support for re-binding on a new
1435   * connection.  Also note that this option will not have any effect on pooled
1436   * connections because defunct pooled connections will be replaced by
1437   * newly-created connections rather than attempting to re-establish the
1438   * existing connection.  Further, auto-reconnect should not be used with
1439   * connections that use StartTLS or some other mechanism to alter the state
1440   * of the connection beyond authentication.
1441   * <BR><BR>
1442   * NOTE:  The use of auto-reconnect is strongly discouraged because it is
1443   * inherently fragile and can only work under very limited circumstances.  It
1444   * is strongly recommended that a connection pool be used instead of the
1445   * auto-reconnect option, even in cases where only a single connection is
1446   * desired.
1447   *
1448   * @param  autoReconnect  Specifies whether associated connections should
1449   *                        attempt to automatically reconnect to the target
1450   *                        server if the connection is lost.
1451   *
1452   * @deprecated  The use of auto-reconnect is strongly discouraged because it
1453   *              is inherently fragile and can only work under very limited
1454   *              circumstances.  It is strongly recommended that a connection
1455   *              pool be used instead of the auto-reconnect option, even in
1456   *              cases where only a single connection is desired.
1457   */
1458  @Deprecated()
1459  public void setAutoReconnect(final boolean autoReconnect)
1460  {
1461    this.autoReconnect = autoReconnect;
1462  }
1463
1464
1465
1466  /**
1467   * Retrieves the name resolver that should be used to resolve host names to IP
1468   * addresses.
1469   *
1470   * @return  The name resolver that should be used to resolve host names to IP
1471   *          addresses.
1472   */
1473  @NotNull()
1474  public NameResolver getNameResolver()
1475  {
1476    return nameResolver;
1477  }
1478
1479
1480
1481  /**
1482   * Sets the name resolver that should be used to resolve host names to IP
1483   * addresses.
1484   *
1485   * @param  nameResolver  The name resolver that should be used to resolve host
1486   *                       names to IP addresses.
1487   */
1488  public void setNameResolver(@Nullable final NameResolver nameResolver)
1489  {
1490    if (nameResolver == null)
1491    {
1492      this.nameResolver = DEFAULT_NAME_RESOLVER;
1493    }
1494    else
1495    {
1496      this.nameResolver = nameResolver;
1497    }
1498  }
1499
1500
1501
1502  /**
1503   * Indicates whether the SDK should allow simple bind operations that contain
1504   * a bind DN but no password.  Binds of this type may represent a security
1505   * vulnerability in client applications because they may cause the client to
1506   * believe that the user is properly authenticated when the server considers
1507   * it to be an unauthenticated connection.
1508   *
1509   * @return  {@code true} if the SDK should allow simple bind operations that
1510   *          contain a bind DN but no password, or {@code false} if not.
1511   */
1512  public boolean bindWithDNRequiresPassword()
1513  {
1514    return bindWithDNRequiresPassword;
1515  }
1516
1517
1518
1519  /**
1520   * Specifies whether the SDK should allow simple bind operations that contain
1521   * a bind DN but no password.
1522   *
1523   * @param  bindWithDNRequiresPassword  Indicates whether the SDK should allow
1524   *                                     simple bind operations that contain a
1525   *                                     bind DN but no password.
1526   */
1527  public void setBindWithDNRequiresPassword(
1528                   final boolean bindWithDNRequiresPassword)
1529  {
1530    this.bindWithDNRequiresPassword = bindWithDNRequiresPassword;
1531  }
1532
1533
1534
1535  /**
1536   * Indicates whether the LDAP SDK should capture a thread stack trace for each
1537   * attempt made to establish a connection.  If this is enabled, then the
1538   * {@link LDAPConnection#getConnectStackTrace()}  method may be used to
1539   * retrieve the stack trace.
1540   *
1541   * @return  {@code true} if a thread stack trace should be captured whenever a
1542   *          connection is established, or {@code false} if not.
1543   */
1544  public boolean captureConnectStackTrace()
1545  {
1546    return captureConnectStackTrace;
1547  }
1548
1549
1550
1551  /**
1552   * Specifies whether the LDAP SDK should capture a thread stack trace for each
1553   * attempt made to establish a connection.
1554   *
1555   * @param  captureConnectStackTrace  Indicates whether to capture a thread
1556   *                                   stack trace for each attempt made to
1557   *                                   establish a connection.
1558   */
1559  public void setCaptureConnectStackTrace(
1560                   final boolean captureConnectStackTrace)
1561  {
1562    this.captureConnectStackTrace = captureConnectStackTrace;
1563  }
1564
1565
1566
1567  /**
1568   * Retrieves the maximum length of time in milliseconds that a connection
1569   * attempt should be allowed to continue before giving up.
1570   *
1571   * @return  The maximum length of time in milliseconds that a connection
1572   *          attempt should be allowed to continue before giving up, or zero
1573   *          to indicate that there should be no connect timeout.
1574   */
1575  public int getConnectTimeoutMillis()
1576  {
1577    return connectTimeoutMillis;
1578  }
1579
1580
1581
1582  /**
1583   * Specifies the maximum length of time in milliseconds that a connection
1584   * attempt should be allowed to continue before giving up.  A value of zero
1585   * indicates that there should be no connect timeout.
1586   *
1587   * @param  connectTimeoutMillis  The maximum length of time in milliseconds
1588   *                               that a connection attempt should be allowed
1589   *                               to continue before giving up.
1590   */
1591  public void setConnectTimeoutMillis(final int connectTimeoutMillis)
1592  {
1593    this.connectTimeoutMillis = connectTimeoutMillis;
1594  }
1595
1596
1597
1598  /**
1599   * Retrieves the maximum length of time in milliseconds that an operation
1600   * should be allowed to block while waiting for a response from the server.
1601   * This may be overridden on a per-operation type basis, so the
1602   * {@link #getResponseTimeoutMillis(OperationType)} method should be used
1603   * instead of this one.
1604   *
1605   * @return  The maximum length of time in milliseconds that an operation
1606   *          should be allowed to block while waiting for a response from the
1607   *          server, or zero if there should not be any default timeout.
1608   */
1609  public long getResponseTimeoutMillis()
1610  {
1611    return responseTimeoutMillis;
1612  }
1613
1614
1615
1616  /**
1617   * Specifies the maximum length of time in milliseconds that an operation
1618   * should be allowed to block while waiting for a response from the server.  A
1619   * value of zero indicates that there should be no timeout.  Note that this
1620   * will override any per-operation type and per-extended operation type
1621   * timeouts that had previously been set.
1622   *
1623   * @param  responseTimeoutMillis  The maximum length of time in milliseconds
1624   *                                that an operation should be allowed to block
1625   *                                while waiting for a response from the
1626   *                                server.
1627   */
1628  public void setResponseTimeoutMillis(final long responseTimeoutMillis)
1629  {
1630    this.responseTimeoutMillis = Math.max(0L, responseTimeoutMillis);
1631    responseTimeoutMillisByExtendedOperationType = Collections.emptyMap();
1632
1633    final EnumMap<OperationType,Long> newOperationTimeouts =
1634         new EnumMap<>(OperationType.class);
1635    for (final OperationType t : OperationType.values())
1636    {
1637      newOperationTimeouts.put(t, this.responseTimeoutMillis);
1638    }
1639    responseTimeoutMillisByOperationType =
1640         Collections.unmodifiableMap(newOperationTimeouts);
1641  }
1642
1643
1644
1645  /**
1646   * Retrieves the maximum length of time in milliseconds that an operation
1647   * of the specified type should be allowed to block while waiting for a
1648   * response from the server.  Note that for extended operations, the response
1649   * timeout may be overridden on a per-request OID basis, so the
1650   * {@link #getExtendedOperationResponseTimeoutMillis(String)} method should be
1651   * used instead of this one for extended operations.
1652   *
1653   * @param  operationType  The operation type for which to make the
1654   *                        determination.  It must not be {@code null}.
1655   *
1656   * @return  The maximum length of time in milliseconds that an operation of
1657   *          the specified type should be allowed to block while waiting for a
1658   *          response from the server, or zero if there should not be any
1659   *          default timeout.
1660   */
1661  public long getResponseTimeoutMillis(
1662                   @NotNull final OperationType operationType)
1663  {
1664    return responseTimeoutMillisByOperationType.get(operationType);
1665  }
1666
1667
1668
1669  /**
1670   * Specifies the maximum length of time in milliseconds that an operation of
1671   * the specified type should be allowed to block while waiting for a response
1672   * from the server.  A value of zero indicates that there should be no
1673   * timeout.
1674   *
1675   * @param  operationType          The operation type for which to set the
1676   *                                response timeout.  It must not be
1677   *                                {@code null}.
1678   * @param  responseTimeoutMillis  The maximum length of time in milliseconds
1679   *                                that an operation should be allowed to block
1680   *                                while waiting for a response from the
1681   *                                server.
1682   */
1683  public void setResponseTimeoutMillis(
1684                   @NotNull final OperationType operationType,
1685                   final long responseTimeoutMillis)
1686  {
1687    final EnumMap<OperationType,Long> newOperationTimeouts =
1688         new EnumMap<>(OperationType.class);
1689    newOperationTimeouts.putAll(responseTimeoutMillisByOperationType);
1690    newOperationTimeouts.put(operationType,
1691         Math.max(0L, responseTimeoutMillis));
1692
1693    responseTimeoutMillisByOperationType = Collections.unmodifiableMap(
1694         newOperationTimeouts);
1695  }
1696
1697
1698
1699  /**
1700   * Retrieves the maximum length of time in milliseconds that an extended
1701   * operation with the specified request OID should be allowed to block while
1702   * waiting for a response from the server.
1703   *
1704   * @param  requestOID  The request OID for the extended operation for which to
1705   *                     make the determination.  It must not be {@code null}.
1706   *
1707   * @return  The maximum length of time in milliseconds that the specified type
1708   *          of extended operation should be allowed to block while waiting for
1709   *          a response from the server, or zero if there should not be any
1710   *          default timeout.
1711   */
1712  public long getExtendedOperationResponseTimeoutMillis(
1713                   @NotNull final String requestOID)
1714  {
1715    final Long timeout =
1716         responseTimeoutMillisByExtendedOperationType.get(requestOID);
1717    if (timeout == null)
1718    {
1719      return responseTimeoutMillisByOperationType.get(OperationType.EXTENDED);
1720    }
1721    else
1722    {
1723      return timeout;
1724    }
1725  }
1726
1727
1728
1729  /**
1730   * Specifies the maximum length of time in milliseconds that an extended
1731   * operation with the specified request OID should be allowed to block while
1732   * waiting for a response from the server.  A value of zero indicates that
1733   * there should be no timeout.
1734   *
1735   * @param  requestOID             The request OID for the extended operation
1736   *                                type for which to set the response timeout.
1737   *                                It must not be {@code null}.
1738   * @param  responseTimeoutMillis  The maximum length of time in milliseconds
1739   *                                that an operation should be allowed to block
1740   *                                while waiting for a response from the
1741   *                                server.
1742   */
1743  public void setExtendedOperationResponseTimeoutMillis(
1744                   @NotNull final String requestOID,
1745                   final long responseTimeoutMillis)
1746  {
1747    final HashMap<String,Long> newExtOpTimeouts =
1748         new HashMap<>(responseTimeoutMillisByExtendedOperationType);
1749    newExtOpTimeouts.put(requestOID, responseTimeoutMillis);
1750    responseTimeoutMillisByExtendedOperationType =
1751         Collections.unmodifiableMap(newExtOpTimeouts);
1752  }
1753
1754
1755
1756  /**
1757   * Indicates whether the LDAP SDK should attempt to abandon any request for
1758   * which no response is received in the maximum response timeout period.
1759   *
1760   * @return  {@code true} if the LDAP SDK should attempt to abandon any request
1761   *          for which no response is received in the maximum response timeout
1762   *          period, or {@code false} if no abandon attempt should be made in
1763   *          this circumstance.
1764   */
1765  public boolean abandonOnTimeout()
1766  {
1767    return abandonOnTimeout;
1768  }
1769
1770
1771
1772  /**
1773   * Specifies whether the LDAP SDK should attempt to abandon any request for
1774   * which no response is received in the maximum response timeout period.
1775   *
1776   * @param  abandonOnTimeout  Indicates whether the LDAP SDK should attempt to
1777   *                           abandon any request for which no response is
1778   *                           received in the maximum response timeout period.
1779   */
1780  public void setAbandonOnTimeout(final boolean abandonOnTimeout)
1781  {
1782    this.abandonOnTimeout = abandonOnTimeout;
1783  }
1784
1785
1786
1787  /**
1788   * Indicates whether to use the SO_KEEPALIVE option for the underlying sockets
1789   * used by associated connections.
1790   *
1791   * @return  {@code true} if the SO_KEEPALIVE option should be used for the
1792   *          underlying sockets, or {@code false} if not.
1793   */
1794  public boolean useKeepAlive()
1795  {
1796    return useKeepAlive;
1797  }
1798
1799
1800
1801  /**
1802   * Specifies whether to use the SO_KEEPALIVE option for the underlying sockets
1803   * used by associated connections.  Changes to this setting will take effect
1804   * only for new sockets, and not for existing sockets.
1805   *
1806   * @param  useKeepAlive  Indicates whether to use the SO_KEEPALIVE option for
1807   *                       the underlying sockets used by associated
1808   *                       connections.
1809   */
1810  public void setUseKeepAlive(final boolean useKeepAlive)
1811  {
1812    this.useKeepAlive = useKeepAlive;
1813  }
1814
1815
1816
1817  /**
1818   * Indicates whether to use the SO_LINGER option for the underlying sockets
1819   * used by associated connections.
1820   *
1821   * @return  {@code true} if the SO_LINGER option should be used for the
1822   *          underlying sockets, or {@code false} if not.
1823   */
1824  public boolean useLinger()
1825  {
1826    return useLinger;
1827  }
1828
1829
1830
1831  /**
1832   * Retrieves the linger timeout in seconds that will be used if the SO_LINGER
1833   * socket option is enabled.
1834   *
1835   * @return  The linger timeout in seconds that will be used if the SO_LINGER
1836   *          socket option is enabled.
1837   */
1838  public int getLingerTimeoutSeconds()
1839  {
1840    return lingerTimeoutSeconds;
1841  }
1842
1843
1844
1845  /**
1846   * Specifies whether to use the SO_LINGER option for the underlying sockets
1847   * used by associated connections.  Changes to this setting will take effect
1848   * only for new sockets, and not for existing sockets.
1849   *
1850   * @param  useLinger             Indicates whether to use the SO_LINGER option
1851   *                               for the underlying sockets used by associated
1852   *                               connections.
1853   * @param  lingerTimeoutSeconds  The linger timeout in seconds that should be
1854   *                               used if this capability is enabled.
1855   */
1856  public void setUseLinger(final boolean useLinger,
1857                           final int lingerTimeoutSeconds)
1858  {
1859    this.useLinger = useLinger;
1860    this.lingerTimeoutSeconds = lingerTimeoutSeconds;
1861  }
1862
1863
1864
1865  /**
1866   * Indicates whether to use the SO_REUSEADDR option for the underlying sockets
1867   * used by associated connections.
1868   *
1869   * @return  {@code true} if the SO_REUSEADDR option should be used for the
1870   *          underlying sockets, or {@code false} if not.
1871   */
1872  public boolean useReuseAddress()
1873  {
1874    return useReuseAddress;
1875  }
1876
1877
1878
1879  /**
1880   * Specifies whether to use the SO_REUSEADDR option for the underlying sockets
1881   * used by associated connections.  Changes to this setting will take effect
1882   * only for new sockets, and not for existing sockets.
1883   *
1884   * @param  useReuseAddress  Indicates whether to use the SO_REUSEADDR option
1885   *                          for the underlying sockets used by associated
1886   *                          connections.
1887   */
1888  public void setUseReuseAddress(final boolean useReuseAddress)
1889  {
1890    this.useReuseAddress = useReuseAddress;
1891  }
1892
1893
1894
1895  /**
1896   * Indicates whether to try to use schema information when reading data from
1897   * the server (e.g., to select the appropriate matching rules for the
1898   * attributes included in a search result entry).
1899   * <BR><BR>
1900   * If the LDAP SDK is configured to make use of schema, then it may be able
1901   * to more accurately perform client-side matching, including methods like
1902   * {@link Filter#matchesEntry(Entry)} or {@link Attribute#hasValue(String)}.
1903   * If both {@code useSchema} and {@code useSPooledSchema} are {@code false},
1904   * then all client-side matching for attribute values will treat them as
1905   * directory string values with a caseIgnoreMatch equality matching rule.  If
1906   * either {@code useSchema} or {@code usePooledSchema} is {@code true}, then
1907   * the LDAP SDK may be able to use the attribute type definitions from that
1908   * schema to determine the appropriate syntax and matching rules to use for
1909   * client-side matching operations involving those attributes.  Any attribute
1910   * types that are not defined in the schema will still be treated as
1911   * case-insensitive directory string values.
1912   *
1913   * @return  {@code true} if schema should be used when reading data from the
1914   *          server, or {@code false} if not.
1915   */
1916  public boolean useSchema()
1917  {
1918    return useSchema;
1919  }
1920
1921
1922
1923  /**
1924   * Specifies whether to try to use schema information when reading data from
1925   * the server (e.g., to select the appropriate matching rules for the
1926   * attributes included in a search result entry).
1927   * <BR><BR>
1928   * If the LDAP SDK is configured to make use of schema, then it may be able
1929   * to more accurately perform client-side matching, including methods like
1930   * {@link Filter#matchesEntry(Entry)} or {@link Attribute#hasValue(String)}.
1931   * If both {@code useSchema} and {@code useSPooledSchema} are {@code false},
1932   * then all client-side matching for attribute values will treat them as
1933   * directory string values with a caseIgnoreMatch equality matching rule.  If
1934   * either {@code useSchema} or {@code usePooledSchema} is {@code true}, then
1935   * the LDAP SDK may be able to use the attribute type definitions from that
1936   * schema to determine the appropriate syntax and matching rules to use for
1937   * client-side matching operations involving those attributes.  Any attribute
1938   * types that are not defined in the schema will still be treated as
1939   * case-insensitive directory string values.
1940   * <BR><BR>
1941   * Note that calling this method with a value of {@code true} will also cause
1942   * the {@code usePooledSchema} setting to be given a value of false, since
1943   * the two values should not both be {@code true} at the same time.
1944   *
1945   * @param  useSchema  Indicates whether to try to use schema information when
1946   *                    reading data from the server.
1947   */
1948  public void setUseSchema(final boolean useSchema)
1949  {
1950    this.useSchema = useSchema;
1951    if (useSchema)
1952    {
1953      usePooledSchema = false;
1954    }
1955  }
1956
1957
1958
1959  /**
1960   * Indicates whether to have connections that are part of a pool try to use
1961   * shared schema information when reading data from the server (e.g., to
1962   * select the appropriate matching rules for the attributes included in a
1963   * search result entry).  If this is {@code true}, then connections in a
1964   * connection pool will share the same cached schema information in a way that
1965   * attempts to reduce network bandwidth and connection establishment time (by
1966   * avoiding the need for each connection to retrieve its own copy of the
1967   * schema).
1968   * <BR><BR>
1969   * If the LDAP SDK is configured to make use of schema, then it may be able
1970   * to more accurately perform client-side matching, including methods like
1971   * {@link Filter#matchesEntry(Entry)} or {@link Attribute#hasValue(String)}.
1972   * If both {@code useSchema} and {@code useSPooledSchema} are {@code false},
1973   * then all client-side matching for attribute values will treat them as
1974   * directory string values with a caseIgnoreMatch equality matching rule.  If
1975   * either {@code useSchema} or {@code usePooledSchema} is {@code true}, then
1976   * the LDAP SDK may be able to use the attribute type definitions from that
1977   * schema to determine the appropriate syntax and matching rules to use for
1978   * client-side matching operations involving those attributes.  Any attribute
1979   * types that are not defined in the schema will still be treated as
1980   * case-insensitive directory string values.
1981   * <BR><BR>
1982   * If pooled schema is to be used, then it may be configured to expire so that
1983   * the schema may be periodically re-retrieved for new connections to allow
1984   * schema updates to be incorporated.  This behavior is controlled by the
1985   * value returned by the {@link #getPooledSchemaTimeoutMillis} method.
1986   *
1987   * @return  {@code true} if all connections in a connection pool should
1988   *          reference the same schema object, or {@code false} if each
1989   *          connection should retrieve its own copy of the schema.
1990   */
1991  public boolean usePooledSchema()
1992  {
1993    return usePooledSchema;
1994  }
1995
1996
1997
1998  /**
1999   * Indicates whether to have connections that are part of a pool try to use
2000   * shared schema information when reading data from the server (e.g., to
2001   * select the appropriate matching rules for the attributes included in a
2002   * search result entry).
2003   * <BR><BR>
2004   * If the LDAP SDK is configured to make use of schema, then it may be able
2005   * to more accurately perform client-side matching, including methods like
2006   * {@link Filter#matchesEntry(Entry)} or {@link Attribute#hasValue(String)}.
2007   * If both {@code useSchema} and {@code useSPooledSchema} are {@code false},
2008   * then all client-side matching for attribute values will treat them as
2009   * directory string values with a caseIgnoreMatch equality matching rule.  If
2010   * either {@code useSchema} or {@code usePooledSchema} is {@code true}, then
2011   * the LDAP SDK may be able to use the attribute type definitions from that
2012   * schema to determine the appropriate syntax and matching rules to use for
2013   * client-side matching operations involving those attributes.  Any attribute
2014   * types that are not defined in the schema will still be treated as
2015   * case-insensitive directory string values.
2016   * <BR><BR>
2017   * Note that calling this method with a value of {@code true} will also cause
2018   * the {@code useSchema} setting to be given a value of false, since the two
2019   * values should not both be {@code true} at the same time.
2020   *
2021   * @param  usePooledSchema  Indicates whether all connections in a connection
2022   *                          pool should reference the same schema object
2023   *                          rather than attempting to retrieve their own copy
2024   *                          of the schema.
2025   */
2026  public void setUsePooledSchema(final boolean usePooledSchema)
2027  {
2028    this.usePooledSchema = usePooledSchema;
2029    if (usePooledSchema)
2030    {
2031      useSchema = false;
2032    }
2033  }
2034
2035
2036
2037  /**
2038   * Retrieves the maximum length of time in milliseconds that a pooled schema
2039   * object should be considered fresh.  If the schema referenced by a
2040   * connection pool is at least this old, then the next connection attempt may
2041   * cause a new version of the schema to be retrieved.
2042   * <BR><BR>
2043   * This will only be used if the {@link #usePooledSchema} method returns
2044   * {@code true}.  A value of zero indicates that the pooled schema will never
2045   * expire.
2046   *
2047   * @return  The maximum length of time, in milliseconds, that a pooled schema
2048   *          object should be considered fresh, or zero if pooled schema
2049   *          objects should never expire.
2050   */
2051  public long getPooledSchemaTimeoutMillis()
2052  {
2053    return pooledSchemaTimeoutMillis;
2054  }
2055
2056
2057
2058  /**
2059   * Specifies the maximum length of time in milliseconds that a pooled schema
2060   * object should be considered fresh.
2061   *
2062   * @param  pooledSchemaTimeoutMillis  The maximum length of time in
2063   *                                    milliseconds that a pooled schema object
2064   *                                    should be considered fresh.  A value
2065   *                                    less than or equal to zero will indicate
2066   *                                    that pooled schema should never expire.
2067   */
2068  public void setPooledSchemaTimeoutMillis(final long pooledSchemaTimeoutMillis)
2069  {
2070    this.pooledSchemaTimeoutMillis = Math.max(0L, pooledSchemaTimeoutMillis);
2071  }
2072
2073
2074
2075  /**
2076   * Indicates whether to operate in synchronous mode, in which at most one
2077   * operation may be in progress at any time on a given connection, which may
2078   * allow it to operate more efficiently and without requiring a separate
2079   * reader thread per connection.  The LDAP SDK will not absolutely enforce
2080   * this restriction, but when operating in this mode correct behavior
2081   * cannot be guaranteed when multiple attempts are made to use a connection
2082   * for multiple concurrent operations.
2083   * <BR><BR>
2084   * Note that if synchronous mode is to be used, then this connection option
2085   * must be set on the connection before any attempt is made to establish the
2086   * connection.  Once the connection has been established, then it will
2087   * continue to operate in synchronous or asynchronous mode based on the
2088   * options in place at the time it was connected.
2089   *
2090   * @return  {@code true} if associated connections should operate in
2091   *          synchronous mode, or {@code false} if not.
2092   */
2093  public boolean useSynchronousMode()
2094  {
2095    return useSynchronousMode;
2096  }
2097
2098
2099
2100  /**
2101   * Specifies whether to operate in synchronous mode, in which at most one
2102   * operation may be in progress at any time on a given connection.
2103   * <BR><BR>
2104   * Note that if synchronous mode is to be used, then this connection option
2105   * must be set on the connection before any attempt is made to establish the
2106   * connection.  Once the connection has been established, then it will
2107   * continue to operate in synchronous or asynchronous mode based on the
2108   * options in place at the time it was connected.
2109   *
2110   * @param  useSynchronousMode  Indicates whether to operate in synchronous
2111   *                             mode.
2112   */
2113  public void setUseSynchronousMode(final boolean useSynchronousMode)
2114  {
2115    this.useSynchronousMode = useSynchronousMode;
2116  }
2117
2118
2119
2120  /**
2121   * Indicates whether to use the TCP_NODELAY option for the underlying sockets
2122   * used by associated connections.
2123   *
2124   * @return  {@code true} if the TCP_NODELAY option should be used for the
2125   *          underlying sockets, or {@code false} if not.
2126   */
2127  public boolean useTCPNoDelay()
2128  {
2129    return useTCPNoDelay;
2130  }
2131
2132
2133
2134  /**
2135   * Specifies whether to use the TCP_NODELAY option for the underlying sockets
2136   * used by associated connections.  Changes to this setting will take effect
2137   * only for new sockets, and not for existing sockets.
2138   *
2139   * @param  useTCPNoDelay  Indicates whether to use the TCP_NODELAY option for
2140   *                        the underlying sockets used by associated
2141   *                        connections.
2142   */
2143  public void setUseTCPNoDelay(final boolean useTCPNoDelay)
2144  {
2145    this.useTCPNoDelay = useTCPNoDelay;
2146  }
2147
2148
2149
2150  /**
2151   * Indicates whether associated connections should attempt to follow any
2152   * referrals that they encounter.
2153   *
2154   * @return  {@code true} if associated connections should attempt to follow
2155   *          any referrals that they encounter, or {@code false} if not.
2156   */
2157  public boolean followReferrals()
2158  {
2159    return followReferrals;
2160  }
2161
2162
2163
2164  /**
2165   * Specifies whether associated connections should attempt to follow any
2166   * referrals that they encounter, using the referral connector for the
2167   * associated connection.
2168   *
2169   * @param  followReferrals  Specifies whether associated connections should
2170   *                          attempt to follow any referrals that they
2171   *                          encounter.
2172   */
2173  public void setFollowReferrals(final boolean followReferrals)
2174  {
2175    this.followReferrals = followReferrals;
2176  }
2177
2178
2179
2180  /**
2181   * Retrieves the maximum number of hops that a connection should take when
2182   * trying to follow a referral.
2183   *
2184   * @return  The maximum number of hops that a connection should take when
2185   *          trying to follow a referral.
2186   */
2187  public int getReferralHopLimit()
2188  {
2189    return referralHopLimit;
2190  }
2191
2192
2193
2194  /**
2195   * Specifies the maximum number of hops that a connection should take when
2196   * trying to follow a referral.
2197   *
2198   * @param  referralHopLimit  The maximum number of hops that a connection
2199   *                           should take when trying to follow a referral.  It
2200   *                           must be greater than zero.
2201   */
2202  public void setReferralHopLimit(final int referralHopLimit)
2203  {
2204    Validator.ensureTrue(referralHopLimit > 0,
2205         "LDAPConnectionOptions.referralHopLimit must be greater than 0.");
2206
2207    this.referralHopLimit = referralHopLimit;
2208  }
2209
2210
2211
2212  /**
2213   * Retrieves the referral connector that will be used to establish and
2214   * optionally authenticate connections to servers when attempting to follow
2215   * referrals, if defined.
2216   *
2217   * @return  The referral connector that will be used to establish and
2218   *          optionally authenticate connections to servers when attempting to
2219   *          follow referrals, or {@code null} if no specific referral
2220   *          connector has been configured and referral connections should be
2221   *          created using the same socket factory and bind request as the
2222   *          connection on which the referral was received.
2223   */
2224  @Nullable()
2225  public ReferralConnector getReferralConnector()
2226  {
2227    return referralConnector;
2228  }
2229
2230
2231
2232  /**
2233   * Specifies the referral connector that should be used to establish and
2234   * optionally authenticate connections to servers when attempting to follow
2235   * referrals.
2236   *
2237   * @param  referralConnector  The referral connector that will be used to
2238   *                            establish and optionally authenticate
2239   *                            connections to servers when attempting to follow
2240   *                            referrals.  It may be {@code null} to indicate
2241   *                            that the same socket factory and bind request
2242   *                            as the connection on which the referral was
2243   *                            received should be used to establish and
2244   *                            authenticate connections for following
2245   *                            referrals.
2246   */
2247  public void setReferralConnector(
2248                   @Nullable final ReferralConnector referralConnector)
2249  {
2250    this.referralConnector = referralConnector;
2251  }
2252
2253
2254
2255  /**
2256   * Retrieves the maximum size in bytes for an LDAP message that a connection
2257   * will attempt to read from the directory server.  If it encounters an LDAP
2258   * message that is larger than this size, then the connection will be
2259   * terminated.
2260   *
2261   * @return  The maximum size in bytes for an LDAP message that a connection
2262   *          will attempt to read from the directory server, or 0 if no limit
2263   *          will be enforced.
2264   */
2265  public int getMaxMessageSize()
2266  {
2267    return maxMessageSizeBytes;
2268  }
2269
2270
2271
2272  /**
2273   * Specifies the maximum size in bytes for an LDAP message that a connection
2274   * will attempt to read from the directory server.  If it encounters an LDAP
2275   * message that is larger than this size, then the connection will be
2276   * terminated.
2277   *
2278   * @param  maxMessageSizeBytes  The maximum size in bytes for an LDAP message
2279   *                              that a connection will attempt to read from
2280   *                              the directory server.  A value less than or
2281   *                              equal to zero indicates that no limit should
2282   *                              be enforced.
2283   */
2284  public void setMaxMessageSize(final int maxMessageSizeBytes)
2285  {
2286    this.maxMessageSizeBytes = Math.max(0, maxMessageSizeBytes);
2287  }
2288
2289
2290
2291  /**
2292   * Retrieves the logger that should be used to record information about
2293   * requests sent and responses received over connections with this set of
2294   * connection options.
2295   *
2296   * @return  The logger that should be used to record information about the
2297   *          requests sent and responses received over connection with this set
2298   *          of options, or {@code null} if no logging should be performed.
2299   */
2300  @Nullable()
2301  public LDAPConnectionLogger getConnectionLogger()
2302  {
2303    return connectionLogger;
2304  }
2305
2306
2307
2308  /**
2309   * Specifies the logger that should be used to record information about
2310   * requests sent and responses received over connections with this set of
2311   * connection options.
2312   *
2313   * @param  connectionLogger  The logger that should be used to record
2314   *                           information about the requests sent and
2315   *                           responses received over connection with this set
2316   *                           of options.  It may be {@code null} if no logging
2317   *                           should be performed.
2318   */
2319  public void setConnectionLogger(
2320                   @Nullable final LDAPConnectionLogger connectionLogger)
2321  {
2322    this.connectionLogger = connectionLogger;
2323  }
2324
2325
2326
2327  /**
2328   * Retrieves the disconnect handler to use for associated connections.
2329   *
2330   * @return  the disconnect handler to use for associated connections, or
2331   *          {@code null} if none is defined.
2332   */
2333  @Nullable()
2334  public DisconnectHandler getDisconnectHandler()
2335  {
2336    return disconnectHandler;
2337  }
2338
2339
2340
2341  /**
2342   * Specifies the disconnect handler to use for associated connections.
2343   *
2344   * @param  handler  The disconnect handler to use for associated connections.
2345   */
2346  public void setDisconnectHandler(@Nullable final DisconnectHandler handler)
2347  {
2348    disconnectHandler = handler;
2349  }
2350
2351
2352
2353  /**
2354   * Retrieves the unsolicited notification handler to use for associated
2355   * connections.
2356   *
2357   * @return  The unsolicited notification handler to use for associated
2358   *          connections, or {@code null} if none is defined.
2359   */
2360  @Nullable()
2361  public UnsolicitedNotificationHandler getUnsolicitedNotificationHandler()
2362  {
2363    return unsolicitedNotificationHandler;
2364  }
2365
2366
2367
2368  /**
2369   * Specifies the unsolicited notification handler to use for associated
2370   * connections.
2371   *
2372   * @param  handler  The unsolicited notification handler to use for associated
2373   *                  connections.
2374   */
2375  public void setUnsolicitedNotificationHandler(
2376                   @Nullable final UnsolicitedNotificationHandler handler)
2377  {
2378    unsolicitedNotificationHandler = handler;
2379  }
2380
2381
2382
2383  /**
2384   * Retrieves the socket receive buffer size, in bytes, that should be
2385   * requested when establishing a connection.
2386   *
2387   * @return  The socket receive buffer size, in bytes, that should be requested
2388   *          when establishing a connection, or zero if the JVM's default size
2389   *          should be used.
2390   */
2391  public int getReceiveBufferSize()
2392  {
2393    return receiveBufferSizeBytes;
2394  }
2395
2396
2397
2398  /**
2399   * Specifies the socket receive buffer size, in bytes, that should be
2400   * requested when establishing a connection.
2401   *
2402   * @param  receiveBufferSizeBytes  The socket receive buffer size, in bytes,
2403   *                                 that should be requested when establishing
2404   *                                 a connection, or zero if the JVM's default
2405   *                                 size should be used.
2406   */
2407  public void setReceiveBufferSize(final int receiveBufferSizeBytes)
2408  {
2409    this.receiveBufferSizeBytes = Math.max(0, receiveBufferSizeBytes);
2410  }
2411
2412
2413
2414  /**
2415   * Retrieves the socket send buffer size, in bytes, that should be requested
2416   * when establishing a connection.
2417   *
2418   * @return  The socket send buffer size, in bytes, that should be requested
2419   *          when establishing a connection, or zero if the JVM's default size
2420   *          should be used.
2421   */
2422  public int getSendBufferSize()
2423  {
2424    return sendBufferSizeBytes;
2425  }
2426
2427
2428
2429  /**
2430   * Specifies the socket send buffer size, in bytes, that should be requested
2431   * when establishing a connection.
2432   *
2433   * @param  sendBufferSizeBytes  The socket send buffer size, in bytes, that
2434   *                              should be requested when establishing a
2435   *                              connection, or zero if the JVM's default size
2436   *                              should be used.
2437   */
2438  public void setSendBufferSize(final int sendBufferSizeBytes)
2439  {
2440    this.sendBufferSizeBytes = Math.max(0, sendBufferSizeBytes);
2441  }
2442
2443
2444
2445  /**
2446   * Indicates whether to allow a socket factory instance (which may be shared
2447   * across multiple connections) to be used create multiple sockets
2448   * concurrently.  In general, socket factory implementations are threadsafe
2449   * and can be to create multiple connections simultaneously across separate
2450   * threads, but this is known to not be the case in some VM implementations
2451   * (e.g., SSL socket factories in IBM JVMs).  This setting may be used to
2452   * indicate whether concurrent socket creation attempts should be allowed
2453   * (which may allow for better and more consistent performance, especially in
2454   * cases where a connection attempt fails due to a timeout) or prevented
2455   * (which may be necessary for non-threadsafe socket factory implementations).
2456   *
2457   * @return  {@code true} if multiple threads should be able to concurrently
2458   *          use the same socket factory instance, or {@code false} if Java
2459   *          synchronization should be used to ensure that no more than one
2460   *          thread is allowed to use a socket factory at any given time.
2461   */
2462  public boolean allowConcurrentSocketFactoryUse()
2463  {
2464    return allowConcurrentSocketFactoryUse;
2465  }
2466
2467
2468
2469  /**
2470   * Specifies whether to allow a socket factory instance (which may be shared
2471   * across multiple connections) to be used create multiple sockets
2472   * concurrently.  In general, socket factory implementations are threadsafe
2473   * and can be to create multiple connections simultaneously across separate
2474   * threads, but this is known to not be the case in some VM implementations
2475   * (e.g., SSL socket factories in IBM JVMs).  This setting may be used to
2476   * indicate whether concurrent socket creation attempts should be allowed
2477   * (which may allow for better and more consistent performance, especially in
2478   * cases where a connection attempt fails due to a timeout) or prevented
2479   * (which may be necessary for non-threadsafe socket factory implementations).
2480   *
2481   * @param  allowConcurrentSocketFactoryUse  Indicates whether to allow a
2482   *                                          socket factory instance to be used
2483   *                                          to create multiple sockets
2484   *                                          concurrently.
2485   */
2486  public void setAllowConcurrentSocketFactoryUse(
2487                   final boolean allowConcurrentSocketFactoryUse)
2488  {
2489    this.allowConcurrentSocketFactoryUse = allowConcurrentSocketFactoryUse;
2490  }
2491
2492
2493
2494  /**
2495   * Retrieves the {@link SSLSocketVerifier} that will be used to perform
2496   * additional validation for any newly-created {@code SSLSocket} instances.
2497   *
2498   * @return  The {@code SSLSocketVerifier} that will be used to perform
2499   *          additional validation for any newly-created {@code SSLSocket}
2500   *          instances.
2501   */
2502  @NotNull()
2503  public SSLSocketVerifier getSSLSocketVerifier()
2504  {
2505    return sslSocketVerifier;
2506  }
2507
2508
2509
2510  /**
2511   * Specifies the {@link SSLSocketVerifier} that will be used to perform
2512   * additional validation for any newly-created {@code SSLSocket} instances.
2513   *
2514   * @param  sslSocketVerifier  The {@code SSLSocketVerifier} that will be used
2515   *                            to perform additional validation for any
2516   *                            newly-created {@code SSLSocket} instances.
2517   */
2518  public void setSSLSocketVerifier(
2519                   @Nullable final SSLSocketVerifier sslSocketVerifier)
2520  {
2521    if (sslSocketVerifier == null)
2522    {
2523      this.sslSocketVerifier = DEFAULT_SSL_SOCKET_VERIFIER;
2524    }
2525    else
2526    {
2527      this.sslSocketVerifier = sslSocketVerifier;
2528    }
2529  }
2530
2531
2532
2533  /**
2534   * Retrieves the value of the specified system property as a boolean.
2535   *
2536   * @param  propertyName  The name of the system property whose value should be
2537   *                       retrieved.
2538   * @param  defaultValue  The default value that will be returned if the system
2539   *                       property is not defined or if its value cannot be
2540   *                       parsed as a boolean.
2541   *
2542   * @return  The value of the specified system property as an boolean, or the
2543   *          default value if the system property is not set with a valid
2544   *          value.
2545   */
2546  static boolean getSystemProperty(@NotNull final String propertyName,
2547                                   final boolean defaultValue)
2548  {
2549    final String propertyValue = StaticUtils.getSystemProperty(propertyName);
2550    if (propertyValue == null)
2551    {
2552      if (Debug.debugEnabled())
2553      {
2554        Debug.debug(Level.FINE, DebugType.OTHER,
2555             "Using the default value of " + defaultValue + " for system " +
2556                  "property '" + propertyName + "' that is not set.");
2557      }
2558
2559      return defaultValue;
2560    }
2561
2562    if (propertyValue.equalsIgnoreCase("true"))
2563    {
2564      if (Debug.debugEnabled())
2565      {
2566        Debug.debug(Level.INFO, DebugType.OTHER,
2567             "Using value '" + propertyValue + "' set for system property '" +
2568                  propertyName + "'.");
2569      }
2570
2571      return true;
2572    }
2573    else if (propertyValue.equalsIgnoreCase("false"))
2574    {
2575      if (Debug.debugEnabled())
2576      {
2577        Debug.debug(Level.INFO, DebugType.OTHER,
2578             "Using value '" + propertyValue + "' set for system property '" +
2579                  propertyName + "'.");
2580      }
2581
2582      return false;
2583    }
2584    else
2585    {
2586      if (Debug.debugEnabled())
2587      {
2588        Debug.debug(Level.WARNING, DebugType.OTHER,
2589             "Invalid value '" + propertyValue + "' set for system property '" +
2590                  propertyName + "'.  The value was expected to be either " +
2591                  "'true' or 'false'.  The default value of " + defaultValue +
2592                  " will be used instead of the configured value.");
2593      }
2594
2595      return defaultValue;
2596    }
2597  }
2598
2599
2600
2601  /**
2602   * Retrieves the value of the specified system property as an integer.
2603   *
2604   * @param  propertyName  The name of the system property whose value should be
2605   *                       retrieved.
2606   * @param  defaultValue  The default value that will be returned if the system
2607   *                       property is not defined or if its value cannot be
2608   *                       parsed as an integer.
2609   *
2610   * @return  The value of the specified system property as an integer, or the
2611   *          default value if the system property is not set with a valid
2612   *          value.
2613   */
2614  static int getSystemProperty(@NotNull final String propertyName,
2615                               final int defaultValue)
2616  {
2617    final String propertyValueString =
2618         StaticUtils.getSystemProperty(propertyName);
2619    if (propertyValueString == null)
2620    {
2621      if (Debug.debugEnabled())
2622      {
2623        Debug.debug(Level.FINE, DebugType.OTHER,
2624             "Using the default value of " + defaultValue + " for system " +
2625                  "property '" + propertyName + "' that is not set.");
2626      }
2627
2628      return defaultValue;
2629    }
2630
2631    try
2632    {
2633      final int propertyValueInt = Integer.parseInt(propertyValueString);
2634      if (Debug.debugEnabled())
2635      {
2636        Debug.debug(Level.INFO, DebugType.OTHER,
2637             "Using value " + propertyValueInt + " set for system property '" +
2638                  propertyName + "'.");
2639      }
2640
2641      return propertyValueInt;
2642    }
2643    catch (final Exception e)
2644    {
2645      if (Debug.debugEnabled())
2646      {
2647        Debug.debugException(e);
2648        Debug.debug(Level.WARNING, DebugType.OTHER,
2649             "Invalid value '" + propertyValueString + "' set for system " +
2650                  "property '" + propertyName + "'.  The value was expected " +
2651                  "to be an integer.  The default value of " + defaultValue +
2652                  "will be used instead of the configured value.",
2653             e);
2654      }
2655
2656      return defaultValue;
2657    }
2658  }
2659
2660
2661
2662  /**
2663   * Retrieves the value of the specified system property as a long.
2664   *
2665   * @param  propertyName  The name of the system property whose value should be
2666   *                       retrieved.
2667   * @param  defaultValue  The default value that will be returned if the system
2668   *                       property is not defined or if its value cannot be
2669   *                       parsed as a long.
2670   *
2671   * @return  The value of the specified system property as a long, or the
2672   *          default value if the system property is not set with a valid
2673   *          value.
2674   */
2675  @Nullable()
2676  static Long getSystemProperty(@NotNull final String propertyName,
2677                                @Nullable final Long defaultValue)
2678  {
2679    final String propertyValueString =
2680         StaticUtils.getSystemProperty(propertyName);
2681    if (propertyValueString == null)
2682    {
2683      if (Debug.debugEnabled())
2684      {
2685        Debug.debug(Level.FINE, DebugType.OTHER,
2686             "Using the default value of " + defaultValue + " for system " +
2687                  "property '" + propertyName + "' that is not set.");
2688      }
2689
2690      return defaultValue;
2691    }
2692
2693    try
2694    {
2695      final long propertyValueLong = Long.parseLong(propertyValueString);
2696      if (Debug.debugEnabled())
2697      {
2698        Debug.debug(Level.INFO, DebugType.OTHER,
2699             "Using value " + propertyValueLong + " set for system property '" +
2700                  propertyName + "'.");
2701      }
2702
2703      return propertyValueLong;
2704    }
2705    catch (final Exception e)
2706    {
2707      if (Debug.debugEnabled())
2708      {
2709        Debug.debugException(e);
2710        Debug.debug(Level.WARNING, DebugType.OTHER,
2711             "Invalid value '" + propertyValueString + "' set for system " +
2712                  "property '" + propertyName + "'.  The value was expected " +
2713                  "to be a long.  The default value of " + defaultValue +
2714                  "will be used instead of the configured value.",
2715             e);
2716      }
2717
2718      return defaultValue;
2719    }
2720  }
2721
2722
2723
2724  /**
2725   * Retrieves a string representation of this LDAP connection.
2726   *
2727   * @return  A string representation of this LDAP connection.
2728   */
2729  @Override()
2730  @NotNull()
2731  public String toString()
2732  {
2733    final StringBuilder buffer = new StringBuilder();
2734    toString(buffer);
2735    return buffer.toString();
2736  }
2737
2738
2739
2740  /**
2741   * Appends a string representation of this LDAP connection to the provided
2742   * buffer.
2743   *
2744   * @param  buffer  The buffer to which to append a string representation of
2745   *                 this LDAP connection.
2746   */
2747  public void toString(@NotNull final StringBuilder buffer)
2748  {
2749    buffer.append("LDAPConnectionOptions(autoReconnect=");
2750    buffer.append(autoReconnect);
2751    buffer.append(", nameResolver=");
2752    nameResolver.toString(buffer);
2753    buffer.append(", bindWithDNRequiresPassword=");
2754    buffer.append(bindWithDNRequiresPassword);
2755    buffer.append(", followReferrals=");
2756    buffer.append(followReferrals);
2757    if (followReferrals)
2758    {
2759      buffer.append(", referralHopLimit=");
2760      buffer.append(referralHopLimit);
2761    }
2762    if (referralConnector != null)
2763    {
2764      buffer.append(", referralConnectorClass=");
2765      buffer.append(referralConnector.getClass().getName());
2766    }
2767    buffer.append(", useKeepAlive=");
2768    buffer.append(useKeepAlive);
2769    buffer.append(", useLinger=");
2770    if (useLinger)
2771    {
2772      buffer.append("true, lingerTimeoutSeconds=");
2773      buffer.append(lingerTimeoutSeconds);
2774    }
2775    else
2776    {
2777      buffer.append("false");
2778    }
2779    buffer.append(", useReuseAddress=");
2780    buffer.append(useReuseAddress);
2781    buffer.append(", useSchema=");
2782    buffer.append(useSchema);
2783    buffer.append(", usePooledSchema=");
2784    buffer.append(usePooledSchema);
2785    buffer.append(", pooledSchemaTimeoutMillis=");
2786    buffer.append(pooledSchemaTimeoutMillis);
2787    buffer.append(", useSynchronousMode=");
2788    buffer.append(useSynchronousMode);
2789    buffer.append(", useTCPNoDelay=");
2790    buffer.append(useTCPNoDelay);
2791    buffer.append(", captureConnectStackTrace=");
2792    buffer.append(captureConnectStackTrace);
2793    buffer.append(", connectTimeoutMillis=");
2794    buffer.append(connectTimeoutMillis);
2795    buffer.append(", responseTimeoutMillis=");
2796    buffer.append(responseTimeoutMillis);
2797
2798    for (final Map.Entry<OperationType,Long> e :
2799         responseTimeoutMillisByOperationType.entrySet())
2800    {
2801      buffer.append(", responseTimeoutMillis.");
2802      buffer.append(e.getKey().name());
2803      buffer.append('=');
2804      buffer.append(e.getValue());
2805    }
2806
2807    for (final Map.Entry<String,Long> e :
2808         responseTimeoutMillisByExtendedOperationType.entrySet())
2809    {
2810      buffer.append(", responseTimeoutMillis.EXTENDED.");
2811      buffer.append(e.getKey());
2812      buffer.append('=');
2813      buffer.append(e.getValue());
2814    }
2815
2816    buffer.append(", abandonOnTimeout=");
2817    buffer.append(abandonOnTimeout);
2818    buffer.append(", maxMessageSizeBytes=");
2819    buffer.append(maxMessageSizeBytes);
2820    buffer.append(", receiveBufferSizeBytes=");
2821    buffer.append(receiveBufferSizeBytes);
2822    buffer.append(", sendBufferSizeBytes=");
2823    buffer.append(sendBufferSizeBytes);
2824    buffer.append(", allowConcurrentSocketFactoryUse=");
2825    buffer.append(allowConcurrentSocketFactoryUse);
2826
2827    if (connectionLogger != null)
2828    {
2829      buffer.append(", connectionLoggerClass=");
2830      buffer.append(connectionLogger.getClass().getName());
2831    }
2832
2833    if (disconnectHandler != null)
2834    {
2835      buffer.append(", disconnectHandlerClass=");
2836      buffer.append(disconnectHandler.getClass().getName());
2837    }
2838
2839    if (unsolicitedNotificationHandler != null)
2840    {
2841      buffer.append(", unsolicitedNotificationHandlerClass=");
2842      buffer.append(unsolicitedNotificationHandler.getClass().getName());
2843    }
2844
2845    buffer.append(", sslSocketVerifierClass='");
2846    buffer.append(sslSocketVerifier.getClass().getName());
2847    buffer.append('\'');
2848
2849    buffer.append(')');
2850  }
2851}