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