001 /*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk;
022
023
024
025 import com.unboundid.util.StaticUtils;
026 import com.unboundid.util.ssl.SSLSocketVerifier;
027 import com.unboundid.util.ssl.TrustAllSSLSocketVerifier;
028
029 import static com.unboundid.util.Validator.*;
030
031
032
033 /**
034 * This class provides a data structure that may be used to configure a number
035 * of connection-related properties. Elements included in the set of connection
036 * options include:
037 * <UL>
038 * <LI>A flag that indicates whether the SDK should attempt to automatically
039 * re-establish a connection if it is unexpectedly closed. By default,
040 * it will not attempt to do so.</LI>
041 * <LI>A flag that indicates whether simple bind attempts that contain a
042 * non-empty DN will be required to have a non-empty password. By
043 * default, a password will be required in such cases.</LI>
044 * <LI>A flag that indicates whether to automatically attempt to follow any
045 * referrals that may be returned by the server. By default, it will not
046 * automatically attempt to follow referrals.</LI>
047 * <LI>A referral hop limit, which indicates the maximum number of hops that
048 * the connection may take when trying to follow a referral. The default
049 * referral hop limit is five.</LI>
050 * <LI>The referral connector that should be used to create and optionally
051 * authenticate connections used to follow referrals encountered during
052 * processing. By default, referral connections will use the same socket
053 * factory and bind request as the client connection on which the referral
054 * was received.</LI>
055 * <LI>A flag that indicates whether to use the SO_KEEPALIVE socket option to
056 * attempt to more quickly detect when idle TCP connections have been lost
057 * or to prevent them from being unexpectedly closed by intermediate
058 * network hardware. By default, the SO_KEEPALIVE socket option will be
059 * used.</LI>
060 * <LI>A flag that indicates whether to use the SO_LINGER socket option to
061 * indicate how long a connection should linger after it has been closed,
062 * and a value that specifies the length of time that it should linger.
063 * By default, the SO_LINGER option will be used with a timeout of 5
064 * seconds.</LI>
065 * <LI>A flag that indicates whether to use the SO_REUSEADDR socket option to
066 * indicate that a socket in a TIME_WAIT state may be reused. By default,
067 * the SO_REUSEADDR socket option will be used.</LI>
068 * <LI>A flag that indicates whether to operate in synchronous mode, in which
069 * connections may exhibit better performance and will not require a
070 * separate reader thread, but will not allow multiple concurrent
071 * operations to be used on the same connection.</LI>
072 * <LI>A flag that indicates whether to use the TCP_NODELAY socket option to
073 * indicate that any data written to the socket will be sent immediately
074 * rather than delaying for a short amount of time to see if any more data
075 * is to be sent that could potentially be included in the same packet.
076 * By default, the TCP_NODELAY socket option will be used.</LI>
077 * <LI>A value which specifies the maximum length of time in milliseconds that
078 * an attempt to establish a connection should be allowed to block before
079 * failing. By default, a timeout of 60,000 milliseconds (1 minute) will
080 * be used.</LI>
081 * <LI>A value which specifies the default timeout in milliseconds that the
082 * SDK should wait for a response from the server before failing. By
083 * default, a timeout of 300,000 milliseconds (5 minutes) will be
084 * used.</LI>
085 * <LI>A flag that indicates whether to attempt to abandon any request for
086 * which no response is received after waiting for the maximum response
087 * timeout. By default, no abandon request will be sent.</LI>
088 * <LI>A value which specifies the largest LDAP message size that the SDK will
089 * be willing to read from the directory server. By default, the SDK will
090 * not allow responses larger than 20971520 bytes (20MB). If it
091 * encounters a message that may be larger than the maximum allowed
092 * message size, then the SDK will terminate the connection to the
093 * server.</LI>
094 * <LI>The {@code DisconnectHandler} that should be used to receive
095 * notification if connection is disconnected for any reason. By default,
096 * no {@code DisconnectHandler} will be used.</LI>
097 * <LI>The {@code UnsolicitedNotificationHandler} that should be used to
098 * receive notification about any unsolicited notifications returned by
099 * the server. By default, no {@code UnsolicitedNotificationHandler} will
100 * be used.</LI>
101 * <LI>A flag that indicates whether to capture a thread stack trace whenever
102 * a new connection is established. Capturing a thread stack trace when
103 * establishing a connection may be marginally expensive, but can be
104 * useful for debugging certain kinds of problems like leaked connections
105 * (connections that are established but never explicitly closed). By
106 * default, connect stack traces will not be captured.</LI>
107 * <LI>A flag that indicates whether connections should try to retrieve schema
108 * information from the server, which may be used to better determine
109 * which matching rules should be used when comparing attribute values.
110 * By default, server schema information will not be retrieved.</LI>
111 * <LI>The size of the socket receive buffer, which may be used for
112 * temporarily holding data received from the directory server until it
113 * can be read and processed by the LDAP SDK. By default, the receive
114 * buffer size will be automatically determined by the JVM based on the
115 * underlying system settings.</LI>
116 * <LI>The size of the socket send buffer, which may be used for temporarily
117 * holding data to be sent to the directory server until it can actually
118 * be transmitted over the network. By default, the send buffer size will
119 * be automatically determined by the JVM based on the underlying system
120 * settings.</LI>
121 * <LI>A flag which indicates whether to allow a single socket factory instance
122 * (which may be shared across multiple connections) to be used to create
123 * multiple concurrent connections. This offers better and more
124 * predictable performance on some JVM implementations (especially when
125 * connection attempts fail as a result of a connection timeout), but some
126 * JVMs are known to use non-threadsafe socket factory implementations and
127 * may fail from concurrent use (for example, at least some IBM JVMs
128 * exhibit this behavior). By default, Sun/Oracle JVMs will allow
129 * concurrent socket factory use, but JVMs from other vendors will use
130 * synchronization to ensure that a socket factory will only be allowed to
131 * create one connection at a time.</LI>
132 * <LI>A class that may be used to perform additional verification (e.g.,
133 * hostname validation) for any {@code SSLSocket} instances created. By
134 * default, no special verification will be performed.</LI>
135 * </UL>
136 */
137 public final class LDAPConnectionOptions
138 {
139 /**
140 * The default value ({@code false}) for the setting that controls whether to
141 * attempt to abandon any request for which no response is received within the
142 * maximum response timeout.
143 */
144 static final boolean DEFAULT_ABANDON_ON_TIMEOUT = false;
145
146
147
148 /**
149 * The default value ({@code false}) for the setting that controls whether to
150 * automatically attempt to reconnect if a connection is unexpectedly lost.
151 */
152 static final boolean DEFAULT_AUTO_RECONNECT = false;
153
154
155
156 /**
157 * The default value ({@code true}) for the setting that controls whether
158 * simple bind requests with a DN are also required to contain a password.
159 */
160 static final boolean DEFAULT_BIND_WITH_DN_REQUIRES_PASSWORD = true;
161
162
163
164 /**
165 * The default value ({@code false}) for the setting that controls whether to
166 * capture a thread stack trace whenever an attempt is made to establish a
167 * connection.
168 */
169 static final boolean DEFAULT_CAPTURE_CONNECT_STACK_TRACE = false;
170
171
172
173 /**
174 * The default value ({@code false}) for the setting that controls whether to
175 * attempt to automatically follow referrals.
176 */
177 static final boolean DEFAULT_FOLLOW_REFERRALS = false;
178
179
180
181 /**
182 * The default value ({@code false}) for the setting that controls whether all
183 * connections in a connection pool should use the same cached schema object.
184 */
185 static final boolean DEFAULT_USE_POOLED_SCHEMA = false;
186
187
188
189 /**
190 * The default value ({@code true}) for the setting that controls whether to
191 * use the {@code SO_KEEPALIVE} socket option.
192 */
193 static final boolean DEFAULT_USE_KEEPALIVE = true;
194
195
196
197 /**
198 * The default value ({@code true}) for the setting that controls whether to
199 * use the {@code SO_LINGER} socket option.
200 */
201 static final boolean DEFAULT_USE_LINGER = true;
202
203
204
205 /**
206 * The default value ({@code true}) for the setting that controls whether to
207 * use the {@code SO_REUSEADDR} socket option.
208 */
209 static final boolean DEFAULT_USE_REUSE_ADDRESS = true;
210
211
212
213 /**
214 * The default value ({@code false}) for the setting that controls whether to
215 * use schema when reading data from the server.
216 */
217 static final boolean DEFAULT_USE_SCHEMA = false;
218
219
220
221 /**
222 * The default value ({@code false}) for the setting that controls whether to
223 * operate in synchronous mode, in which only a single outstanding operation
224 * may be in progress on an associated connection at any given time.
225 */
226 static final boolean DEFAULT_USE_SYNCHRONOUS_MODE = false;
227
228
229
230 /**
231 * The default value ({@code true}) for the setting that controls whether to
232 * use the {@code TCP_NODELAY} socket option.
233 */
234 static final boolean DEFAULT_USE_TCP_NODELAY = true;
235
236
237
238 /**
239 * The default value (60000) for the setting that controls the timeout in
240 * milliseconds when trying to establish a new connection.
241 */
242 static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 60000;
243
244
245
246 /**
247 * The default value (5) for the setting that controls the timeout in seconds
248 * that will be used with the {@code SO_LINGER} socket option.
249 */
250 static final int DEFAULT_LINGER_TIMEOUT_SECONDS = 5;
251
252
253
254 /**
255 * The default value (20971520 bytes, or 20MB) for the setting that controls
256 * the maximum LDAP message size in bytes that will be allowed when reading
257 * data from a directory server.
258 */
259 static final int DEFAULT_MAX_MESSAGE_SIZE = 20971520;
260
261
262
263 /**
264 * The default size to use for the receive buffer.
265 */
266 static final int DEFAULT_RECEIVE_BUFFER_SIZE = 0;
267
268
269
270 /**
271 * The default value (5) for the setting that controls the referral hop limit.
272 */
273 static final int DEFAULT_REFERRAL_HOP_LIMIT = 5;
274
275
276
277 /**
278 * The default size to use for the send buffer.
279 */
280 static final int DEFAULT_SEND_BUFFER_SIZE = 0;
281
282
283
284 /**
285 * The default value (3600000 milliseconds, or one hour) for the setting that
286 * controls the default pooled schema timeout.
287 */
288 static final long DEFAULT_POOLED_SCHEMA_TIMEOUT_MILLIS = 3600000L;
289
290
291
292 /**
293 * The default value (300000) for the setting that controls the default
294 * response timeout in milliseconds.
295 */
296 static final long DEFAULT_RESPONSE_TIMEOUT_MILLIS = 300000L;
297
298
299
300 /**
301 * The default value for the setting that controls the default behavior with
302 * regard to whether to allow concurrent use of a socket factory to create
303 * client connections.
304 */
305 static final boolean DEFAULT_ALLOW_CONCURRENT_SOCKET_FACTORY_USE;
306 static
307 {
308 final String vmVendor =
309 StaticUtils.toLowerCase(System.getProperty("java.vm.vendor"));
310 DEFAULT_ALLOW_CONCURRENT_SOCKET_FACTORY_USE = ((vmVendor != null) &&
311 (vmVendor.contains("sun microsystems") ||
312 vmVendor.contains("oracle") ||
313 vmVendor.contains("apple")));
314 }
315
316
317
318 /**
319 * The default {@code SSLSocketVerifier} instance that will be used for
320 * performing extra validation for {@code SSLSocket} instances.
321 */
322 static final SSLSocketVerifier DEFAULT_SSL_SOCKET_VERIFIER =
323 TrustAllSSLSocketVerifier.getInstance();
324
325
326
327 // Indicates whether to send an abandon request for any operation for which no
328 // response is received in the maximum response timeout.
329 private boolean abandonOnTimeout;
330
331 // Indicates whether to use synchronization prevent concurrent use of the
332 // socket factory instance associated with a connection or set of connections.
333 private boolean allowConcurrentSocketFactoryUse;
334
335 // Indicates whether the connection should attempt to automatically reconnect
336 // if the connection to the server is lost.
337 private boolean autoReconnect;
338
339 // Indicates whether to allow simple binds that contain a DN but no password.
340 private boolean bindWithDNRequiresPassword;
341
342 // Indicates whether to capture a thread stack trace whenever an attempt is
343 // made to establish a connection;
344 private boolean captureConnectStackTrace;
345
346 // Indicates whether to attempt to follow any referrals that are encountered.
347 private boolean followReferrals;
348
349 // Indicates whether to use SO_KEEPALIVE for the underlying sockets.
350 private boolean useKeepAlive;
351
352 // Indicates whether to use SO_LINGER for the underlying sockets.
353 private boolean useLinger;
354
355 // Indicates whether to use SO_REUSEADDR for the underlying sockets.
356 private boolean useReuseAddress;
357
358 // Indicates whether all connections in a connection pool should reference
359 // the same schema.
360 private boolean usePooledSchema;
361
362 // Indicates whether to try to use schema information when reading data from
363 // the server.
364 private boolean useSchema;
365
366 // Indicates whether to use synchronous mode in which only a single operation
367 // may be in progress on associated connections at any given time.
368 private boolean useSynchronousMode;
369
370 // Indicates whether to use TCP_NODELAY for the underlying sockets.
371 private boolean useTCPNoDelay;
372
373 // The disconnect handler for associated connections.
374 private DisconnectHandler disconnectHandler;
375
376 // The connect timeout, in milliseconds.
377 private int connectTimeout;
378
379 // The linger timeout to use if SO_LINGER is to be used.
380 private int lingerTimeout;
381
382 // The maximum message size in bytes that will be allowed when reading data
383 // from a directory server.
384 private int maxMessageSize;
385
386 // The socket receive buffer size to request.
387 private int receiveBufferSize;
388
389 // The referral hop limit to use if referral following is enabled.
390 private int referralHopLimit;
391
392 // The socket send buffer size to request.
393 private int sendBufferSize;
394
395 // The pooled schema timeout, in milliseconds.
396 private long pooledSchemaTimeout;
397
398 // The response timeout, in milliseconds.
399 private long responseTimeout;
400
401 // Tne default referral connector that should be used for associated
402 // connections.
403 private ReferralConnector referralConnector;
404
405 // The SSLSocketVerifier instance to use to perform extra validation on
406 // newly-established SSLSocket instances.
407 private SSLSocketVerifier sslSocketVerifier;
408
409 // The unsolicited notification handler for associated connections.
410 private UnsolicitedNotificationHandler unsolicitedNotificationHandler;
411
412
413
414 /**
415 * Creates a new set of LDAP connection options with the default settings.
416 */
417 public LDAPConnectionOptions()
418 {
419 abandonOnTimeout = DEFAULT_ABANDON_ON_TIMEOUT;
420 autoReconnect = DEFAULT_AUTO_RECONNECT;
421 bindWithDNRequiresPassword = DEFAULT_BIND_WITH_DN_REQUIRES_PASSWORD;
422 captureConnectStackTrace = DEFAULT_CAPTURE_CONNECT_STACK_TRACE;
423 followReferrals = DEFAULT_FOLLOW_REFERRALS;
424 useKeepAlive = DEFAULT_USE_KEEPALIVE;
425 useLinger = DEFAULT_USE_LINGER;
426 useReuseAddress = DEFAULT_USE_REUSE_ADDRESS;
427 usePooledSchema = DEFAULT_USE_POOLED_SCHEMA;
428 useSchema = DEFAULT_USE_SCHEMA;
429 useSynchronousMode = DEFAULT_USE_SYNCHRONOUS_MODE;
430 useTCPNoDelay = DEFAULT_USE_TCP_NODELAY;
431 connectTimeout = DEFAULT_CONNECT_TIMEOUT_MILLIS;
432 lingerTimeout = DEFAULT_LINGER_TIMEOUT_SECONDS;
433 maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
434 referralHopLimit = DEFAULT_REFERRAL_HOP_LIMIT;
435 pooledSchemaTimeout = DEFAULT_POOLED_SCHEMA_TIMEOUT_MILLIS;
436 responseTimeout = DEFAULT_RESPONSE_TIMEOUT_MILLIS;
437 receiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
438 sendBufferSize = DEFAULT_SEND_BUFFER_SIZE;
439 disconnectHandler = null;
440 referralConnector = null;
441 sslSocketVerifier = DEFAULT_SSL_SOCKET_VERIFIER;
442 unsolicitedNotificationHandler = null;
443
444 allowConcurrentSocketFactoryUse =
445 DEFAULT_ALLOW_CONCURRENT_SOCKET_FACTORY_USE;
446 }
447
448
449
450 /**
451 * Returns a duplicate of this LDAP connection options object that may be
452 * modified without impacting this instance.
453 *
454 * @return A duplicate of this LDAP connection options object that may be
455 * modified without impacting this instance.
456 */
457 public LDAPConnectionOptions duplicate()
458 {
459 final LDAPConnectionOptions o = new LDAPConnectionOptions();
460
461 o.abandonOnTimeout = abandonOnTimeout;
462 o.allowConcurrentSocketFactoryUse = allowConcurrentSocketFactoryUse;
463 o.autoReconnect = autoReconnect;
464 o.bindWithDNRequiresPassword = bindWithDNRequiresPassword;
465 o.captureConnectStackTrace = captureConnectStackTrace;
466 o.followReferrals = followReferrals;
467 o.useKeepAlive = useKeepAlive;
468 o.useLinger = useLinger;
469 o.useReuseAddress = useReuseAddress;
470 o.usePooledSchema = usePooledSchema;
471 o.useSchema = useSchema;
472 o.useSynchronousMode = useSynchronousMode;
473 o.useTCPNoDelay = useTCPNoDelay;
474 o.connectTimeout = connectTimeout;
475 o.lingerTimeout = lingerTimeout;
476 o.maxMessageSize = maxMessageSize;
477 o.pooledSchemaTimeout = pooledSchemaTimeout;
478 o.responseTimeout = responseTimeout;
479 o.referralConnector = referralConnector;
480 o.referralHopLimit = referralHopLimit;
481 o.disconnectHandler = disconnectHandler;
482 o.unsolicitedNotificationHandler = unsolicitedNotificationHandler;
483 o.receiveBufferSize = receiveBufferSize;
484 o.sendBufferSize = sendBufferSize;
485 o.sslSocketVerifier = sslSocketVerifier;
486
487 return o;
488 }
489
490
491
492 /**
493 * Indicates whether associated connections should attempt to automatically
494 * reconnect to the target server if the connection is lost. Note that this
495 * option will not have any effect on pooled connections because defunct
496 * pooled connections will be replaced by newly-created connections rather
497 * than attempting to re-establish the existing connection.
498 *
499 * @return {@code true} if associated connections should attempt to
500 * automatically reconnect to the target server if the connection is
501 * lost, or {@code false} if not.
502 */
503 public boolean autoReconnect()
504 {
505 return autoReconnect;
506 }
507
508
509
510 /**
511 * Specifies whether associated connections should attempt to automatically
512 * reconnect to the target server if the connection is lost. Note that
513 * automatic reconnection will only be available for authenticated clients if
514 * the authentication mechanism used provides support for re-binding on a new
515 * connection. Also note that this option will not have any effect on pooled
516 * connections because defunct pooled connections will be replaced by
517 * newly-created connections rather than attempting to re-establish the
518 * existing connection. Further, auto-reconnect should not be used with
519 * connections that use StartTLS or some other mechanism to alter the state
520 * of the connection beyond authentication.
521 *
522 * @param autoReconnect Specifies whether associated connections should
523 * attempt to automatically reconnect to the target
524 * server if the connection is lost.
525 */
526 public void setAutoReconnect(final boolean autoReconnect)
527 {
528 this.autoReconnect = autoReconnect;
529 }
530
531
532
533 /**
534 * Indicates whether the SDK should allow simple bind operations that contain
535 * a bind DN but no password. Binds of this type may represent a security
536 * vulnerability in client applications because they may cause the client to
537 * believe that the user is properly authenticated when the server considers
538 * it to be an unauthenticated connection.
539 *
540 * @return {@code true} if the SDK should allow simple bind operations that
541 * contain a bind DN but no password, or {@code false} if not.
542 */
543 public boolean bindWithDNRequiresPassword()
544 {
545 return bindWithDNRequiresPassword;
546 }
547
548
549
550 /**
551 * Specifies whether the SDK should allow simple bind operations that contain
552 * a bind DN but no password.
553 *
554 * @param bindWithDNRequiresPassword Indicates whether the SDK should allow
555 * simple bind operations that contain a
556 * bind DN but no password.
557 */
558 public void setBindWithDNRequiresPassword(
559 final boolean bindWithDNRequiresPassword)
560 {
561 this.bindWithDNRequiresPassword = bindWithDNRequiresPassword;
562 }
563
564
565
566 /**
567 * Indicates whether the LDAP SDK should capture a thread stack trace for each
568 * attempt made to establish a connection. If this is enabled, then the
569 * {@code LDAPConnection#getConnectStackTrace()} method may be used to
570 * retrieve the stack trace.
571 *
572 * @return {@code true} if a thread stack trace should be captured whenever a
573 * connection is established, or {@code false} if not.
574 */
575 public boolean captureConnectStackTrace()
576 {
577 return captureConnectStackTrace;
578 }
579
580
581
582 /**
583 * Specifies whether the LDAP SDK should capture a thread stack trace for each
584 * attempt made to establish a connection.
585 *
586 * @param captureConnectStackTrace Indicates whether to capture a thread
587 * stack trace for each attempt made to
588 * establish a connection.
589 */
590 public void setCaptureConnectStackTrace(
591 final boolean captureConnectStackTrace)
592 {
593 this.captureConnectStackTrace = captureConnectStackTrace;
594 }
595
596
597
598 /**
599 * Retrieves the maximum length of time in milliseconds that a connection
600 * attempt should be allowed to continue before giving up.
601 *
602 * @return The maximum length of time in milliseconds that a connection
603 * attempt should be allowed to continue before giving up, or zero
604 * to indicate that there should be no connect timeout.
605 */
606 public int getConnectTimeoutMillis()
607 {
608 return connectTimeout;
609 }
610
611
612
613 /**
614 * Specifies the maximum length of time in milliseconds that a connection
615 * attempt should be allowed to continue before giving up. A value of zero
616 * indicates that there should be no connect timeout.
617 *
618 * @param connectTimeout The maximum length of time in milliseconds that a
619 * connection attempt should be allowed to continue
620 * before giving up.
621 */
622 public void setConnectTimeoutMillis(final int connectTimeout)
623 {
624 this.connectTimeout = connectTimeout;
625 }
626
627
628
629 /**
630 * Retrieves the maximum length of time in milliseconds that an operation
631 * should be allowed to block while waiting for a response from the server.
632 * This may be overridden on a per-operation basis.
633 *
634 * @return The maximum length of time in milliseconds that an operation
635 * should be allowed to block while waiting for a response from the
636 * server, or zero if there should not be any default timeout.
637 */
638 public long getResponseTimeoutMillis()
639 {
640 return responseTimeout;
641 }
642
643
644
645 /**
646 * Specifies the maximum length of time in milliseconds that an operation
647 * should be allowed to block while waiting for a response from the server. A
648 * value of zero indicates that there should be no timeout.
649 *
650 * @param responseTimeout The maximum length of time in milliseconds that an
651 * operation should be allowed to block while waiting
652 * for a response from the server.
653 *
654 */
655 public void setResponseTimeoutMillis(final long responseTimeout)
656 {
657 if (responseTimeout < 0)
658 {
659 this.responseTimeout = 0L;
660 }
661 else
662 {
663 this.responseTimeout = responseTimeout;
664 }
665 }
666
667
668
669 /**
670 * Indicates whether the LDAP SDK should attempt to abandon any request for
671 * which no response is received in the maximum response timeout period.
672 *
673 * @return {@code true} if the LDAP SDK should attempt to abandon any request
674 * for which no response is received in the maximum response timeout
675 * period, or {@code false} if no abandon attempt should be made in
676 * this circumstance.
677 */
678 public boolean abandonOnTimeout()
679 {
680 return abandonOnTimeout;
681 }
682
683
684
685 /**
686 * Specifies whether the LDAP SDK should attempt to abandon any request for
687 * which no response is received in the maximum response timeout period.
688 *
689 * @param abandonOnTimeout Indicates whether the LDAP SDK should attempt to
690 * abandon any request for which no response is
691 * received in the maximum response timeout period.
692 */
693 public void setAbandonOnTimeout(final boolean abandonOnTimeout)
694 {
695 this.abandonOnTimeout = abandonOnTimeout;
696 }
697
698
699
700 /**
701 * Indicates whether to use the SO_KEEPALIVE option for the underlying sockets
702 * used by associated connections.
703 *
704 * @return {@code true} if the SO_KEEPALIVE option should be used for the
705 * underlying sockets, or {@code false} if not.
706 */
707 public boolean useKeepAlive()
708 {
709 return useKeepAlive;
710 }
711
712
713
714 /**
715 * Specifies whether to use the SO_KEEPALIVE option for the underlying sockets
716 * used by associated connections. Changes to this setting will take effect
717 * only for new sockets, and not for existing sockets.
718 *
719 * @param useKeepAlive Indicates whether to use the SO_KEEPALIVE option for
720 * the underlying sockets used by associated
721 * connections.
722 */
723 public void setUseKeepAlive(final boolean useKeepAlive)
724 {
725 this.useKeepAlive = useKeepAlive;
726 }
727
728
729
730 /**
731 * Indicates whether to use the SO_LINGER option for the underlying sockets
732 * used by associated connections.
733 *
734 * @return {@code true} if the SO_LINGER option should be used for the
735 * underlying sockets, or {@code false} if not.
736 */
737 public boolean useLinger()
738 {
739 return useLinger;
740 }
741
742
743
744 /**
745 * Retrieves the linger timeout in seconds that will be used if the SO_LINGER
746 * socket option is enabled.
747 *
748 * @return The linger timeout in seconds that will be used if the SO_LINGER
749 * socket option is enabled.
750 */
751 public int getLingerTimeoutSeconds()
752 {
753 return lingerTimeout;
754 }
755
756
757
758 /**
759 * Specifies whether to use the SO_LINGER option for the underlying sockets
760 * used by associated connections. Changes to this setting will take effect
761 * only for new sockets, and not for existing sockets.
762 *
763 * @param useLinger Indicates whether to use the SO_LINGER option for
764 * the underlying sockets used by associated
765 * connections.
766 * @param lingerTimeout The linger timeout in seconds that should be used if
767 * this capability is enabled.
768 */
769 public void setUseLinger(final boolean useLinger, final int lingerTimeout)
770 {
771 this.useLinger = useLinger;
772 this.lingerTimeout = lingerTimeout;
773 }
774
775
776
777 /**
778 * Indicates whether to use the SO_REUSEADDR option for the underlying sockets
779 * used by associated connections.
780 *
781 * @return {@code true} if the SO_REUSEADDR option should be used for the
782 * underlying sockets, or {@code false} if not.
783 */
784 public boolean useReuseAddress()
785 {
786 return useReuseAddress;
787 }
788
789
790
791 /**
792 * Specifies whether to use the SO_REUSEADDR option for the underlying sockets
793 * used by associated connections. Changes to this setting will take effect
794 * only for new sockets, and not for existing sockets.
795 *
796 * @param useReuseAddress Indicates whether to use the SO_REUSEADDR option
797 * for the underlying sockets used by associated
798 * connections.
799 */
800 public void setUseReuseAddress(final boolean useReuseAddress)
801 {
802 this.useReuseAddress = useReuseAddress;
803 }
804
805
806
807 /**
808 * Indicates whether to try to use schema information when reading data from
809 * the server (e.g., to select the appropriate matching rules for the
810 * attributes included in a search result entry).
811 *
812 * @return {@code true} if schema should be used when reading data from the
813 * server, or {@code false} if not.
814 */
815 public boolean useSchema()
816 {
817 return useSchema;
818 }
819
820
821
822 /**
823 * Specifies whether to try to use schema information when reading data from
824 * the server (e.g., to select the appropriate matching rules for the
825 * attributes included in a search result entry).
826 * <BR><BR>
827 * Note that calling this method with a value of {@code true} will also cause
828 * the {@code usePooledSchema} setting to be given a value of false, since
829 * the two values should not both be {@code true} at the same time.
830 *
831 * @param useSchema Indicates whether to try to use schema information when
832 * reading data from the server.
833 */
834 public void setUseSchema(final boolean useSchema)
835 {
836 this.useSchema = useSchema;
837 if (useSchema)
838 {
839 usePooledSchema = false;
840 }
841 }
842
843
844
845 /**
846 * Indicates whether to have connections that are part of a pool try to use
847 * shared schema information when reading data from the server (e.g., to
848 * select the appropriate matching rules for the attributes included in a
849 * search result entry). If this is {@code true}, then connections in a
850 * connection pool will share the same cached schema information in a way that
851 * attempts to reduce network bandwidth and connection establishment time (by
852 * avoiding the need for each connection to retrieve its own copy of the
853 * schema).
854 * <BR><BR>
855 * If pooled schema is to be used, then it may be configured to expire so that
856 * the schema may be periodically re-retrieved for new connections to allow
857 * schema updates to be incorporated. This behavior is controlled by the
858 * value returned by the {@code getPooledSchemaTimeoutMillis} method.
859 *
860 * @return {@code true} if all connections in a connection pool should
861 * reference the same schema object, or {@code false} if each
862 * connection should retrieve its own copy of the schema.
863 */
864 public boolean usePooledSchema()
865 {
866 return usePooledSchema;
867 }
868
869
870
871 /**
872 * Indicates whether to have connections that are part of a pool try to use
873 * shared schema information when reading data from the server (e.g., to
874 * select the appropriate matching rules for the attributes included in a
875 * search result entry).
876 * <BR><BR>
877 * Note that calling this method with a value of {@code true} will also cause
878 * the {@code useSchema} setting to be given a value of false, since the two
879 * values should not both be {@code true} at the same time.
880 *
881 * @param usePooledSchema Indicates whether all connections in a connection
882 * pool should reference the same schema object
883 * rather than attempting to retrieve their own copy
884 * of the schema.
885 */
886 public void setUsePooledSchema(final boolean usePooledSchema)
887 {
888 this.usePooledSchema = usePooledSchema;
889 if (usePooledSchema)
890 {
891 useSchema = false;
892 }
893 }
894
895
896
897 /**
898 * Retrieves the maximum length of time in milliseconds that a pooled schema
899 * object should be considered fresh. If the schema referenced by a
900 * connection pool is at least this old, then the next connection attempt may
901 * cause a new version of the schema to be retrieved.
902 * <BR><BR>
903 * This will only be used if the {@code usePooledSchema} method returns
904 * {@code true}. A value of zero indicates that the pooled schema will never
905 * expire.
906 *
907 * @return The maximum length of time, in milliseconds, that a pooled schema
908 * object should be considered fresh, or zero if pooled schema
909 * objects should never expire.
910 */
911 public long getPooledSchemaTimeoutMillis()
912 {
913 return pooledSchemaTimeout;
914 }
915
916
917
918 /**
919 * Specifies the maximum length of time in milliseconds that a pooled schema
920 * object should be considered fresh.
921 *
922 * @param pooledSchemaTimeout The maximum length of time in milliseconds
923 * that a pooled schema object should be
924 * considered fresh. A value less than or equal
925 * to zero will indicate that pooled schema
926 * should never expire.
927 */
928 public void setPooledSchemaTimeoutMillis(final long pooledSchemaTimeout)
929 {
930 if (pooledSchemaTimeout < 0)
931 {
932 this.pooledSchemaTimeout = 0L;
933 }
934 else
935 {
936 this.pooledSchemaTimeout = pooledSchemaTimeout;
937 }
938 }
939
940
941
942 /**
943 * Indicates whether to operate in synchronous mode, in which at most one
944 * operation may be in progress at any time on a given connection, which may
945 * allow it to operate more efficiently and without requiring a separate
946 * reader thread per connection. The LDAP SDK will not absolutely enforce
947 * this restriction, but when operating in this mode correct behavior
948 * cannot be guaranteed when multiple attempts are made to use a connection
949 * for multiple concurrent operations.
950 * <BR><BR>
951 * Note that if synchronous mode is to be used, then this connection option
952 * must be set on the connection before any attempt is made to establish the
953 * connection. Once the connection has been established, then it will
954 * continue to operate in synchronous or asynchronous mode based on the
955 * options in place at the time it was connected.
956 *
957 * @return {@code true} if associated connections should operate in
958 * synchronous mode, or {@code false} if not.
959 */
960 public boolean useSynchronousMode()
961 {
962 return useSynchronousMode;
963 }
964
965
966
967 /**
968 * Specifies whether to operate in synchronous mode, in which at most one
969 * operation may be in progress at any time on a given connection.
970 * <BR><BR>
971 * Note that if synchronous mode is to be used, then this connection option
972 * must be set on the connection before any attempt is made to establish the
973 * connection. Once the connection has been established, then it will
974 * continue to operate in synchronous or asynchronous mode based on the
975 * options in place at the time it was connected.
976 *
977 * @param useSynchronousMode Indicates whether to operate in synchronous
978 * mode.
979 */
980 public void setUseSynchronousMode(final boolean useSynchronousMode)
981 {
982 this.useSynchronousMode = useSynchronousMode;
983 }
984
985
986
987 /**
988 * Indicates whether to use the TCP_NODELAY option for the underlying sockets
989 * used by associated connections.
990 *
991 * @return {@code true} if the TCP_NODELAY option should be used for the
992 * underlying sockets, or {@code false} if not.
993 */
994 public boolean useTCPNoDelay()
995 {
996 return useTCPNoDelay;
997 }
998
999
1000
1001 /**
1002 * Specifies whether to use the TCP_NODELAY option for the underlying sockets
1003 * used by associated connections. Changes to this setting will take effect
1004 * only for new sockets, and not for existing sockets.
1005 *
1006 * @param useTCPNoDelay Indicates whether to use the TCP_NODELAY option for
1007 * the underlying sockets used by associated
1008 * connections.
1009 */
1010 public void setUseTCPNoDelay(final boolean useTCPNoDelay)
1011 {
1012 this.useTCPNoDelay = useTCPNoDelay;
1013 }
1014
1015
1016
1017 /**
1018 * Indicates whether associated connections should attempt to follow any
1019 * referrals that they encounter.
1020 *
1021 * @return {@code true} if associated connections should attempt to follow
1022 * any referrals that they encounter, or {@code false} if not.
1023 */
1024 public boolean followReferrals()
1025 {
1026 return followReferrals;
1027 }
1028
1029
1030
1031 /**
1032 * Specifies whether associated connections should attempt to follow any
1033 * referrals that they encounter, using the referral connector for the
1034 * associated connection.
1035 *
1036 * @param followReferrals Specifies whether associated connections should
1037 * attempt to follow any referrals that they
1038 * encounter.
1039 */
1040 public void setFollowReferrals(final boolean followReferrals)
1041 {
1042 this.followReferrals = followReferrals;
1043 }
1044
1045
1046
1047 /**
1048 * Retrieves the maximum number of hops that a connection should take when
1049 * trying to follow a referral.
1050 *
1051 * @return The maximum number of hops that a connection should take when
1052 * trying to follow a referral.
1053 */
1054 public int getReferralHopLimit()
1055 {
1056 return referralHopLimit;
1057 }
1058
1059
1060
1061 /**
1062 * Specifies the maximum number of hops that a connection should take when
1063 * trying to follow a referral.
1064 *
1065 * @param referralHopLimit The maximum number of hops that a connection
1066 * should take when trying to follow a referral. It
1067 * must be greater than zero.
1068 */
1069 public void setReferralHopLimit(final int referralHopLimit)
1070 {
1071 ensureTrue(referralHopLimit > 0,
1072 "LDAPConnectionOptions.referralHopLimit must be greater than 0.");
1073
1074 this.referralHopLimit = referralHopLimit;
1075 }
1076
1077
1078
1079 /**
1080 * Retrieves the referral connector that will be used to establish and
1081 * optionally authenticate connections to servers when attempting to follow
1082 * referrals, if defined.
1083 *
1084 * @return The referral connector that will be used to establish and
1085 * optionally authenticate connections to servers when attempting to
1086 * follow referrals, or {@code null} if no specific referral
1087 * connector has been configured and referral connections should be
1088 * created using the same socket factory and bind request as the
1089 * connection on which the referral was received.
1090 */
1091 public ReferralConnector getReferralConnector()
1092 {
1093 return referralConnector;
1094 }
1095
1096
1097
1098 /**
1099 * Specifies the referral connector that should be used to establish and
1100 * optionally authenticate connections to servers when attempting to follow
1101 * referrals.
1102 *
1103 * @param referralConnector The referral connector that will be used to
1104 * establish and optionally authenticate
1105 * connections to servers when attempting to follow
1106 * referrals. It may be {@code null} to indicate
1107 * that the same socket factory and bind request
1108 * as the connection on which the referral was
1109 * received should be used to establish and
1110 * authenticate connections for following
1111 * referrals.
1112 */
1113 public void setReferralConnector(final ReferralConnector referralConnector)
1114 {
1115 this.referralConnector = referralConnector;
1116 }
1117
1118
1119
1120 /**
1121 * Retrieves the maximum size in bytes for an LDAP message that a connection
1122 * will attempt to read from the directory server. If it encounters an LDAP
1123 * message that is larger than this size, then the connection will be
1124 * terminated.
1125 *
1126 * @return The maximum size in bytes for an LDAP message that a connection
1127 * will attempt to read from the directory server, or 0 if no limit
1128 * will be enforced.
1129 */
1130 public int getMaxMessageSize()
1131 {
1132 return maxMessageSize;
1133 }
1134
1135
1136
1137 /**
1138 * Specifies the maximum size in bytes for an LDAP message that a connection
1139 * will attempt to read from the directory server. If it encounters an LDAP
1140 * message that is larger than this size, then the connection will be
1141 * terminated.
1142 *
1143 * @param maxMessageSize The maximum size in bytes for an LDAP message that
1144 * a connection will attempt to read from the
1145 * directory server. A value less than or equal to
1146 * zero indicates that no limit should be enforced.
1147 */
1148 public void setMaxMessageSize(final int maxMessageSize)
1149 {
1150 if (maxMessageSize > 0)
1151 {
1152 this.maxMessageSize = maxMessageSize;
1153 }
1154 else
1155 {
1156 this.maxMessageSize = 0;
1157 }
1158 }
1159
1160
1161
1162 /**
1163 * Retrieves the disconnect handler to use for associated connections.
1164 *
1165 * @return the disconnect handler to use for associated connections, or
1166 * {@code null} if none is defined.
1167 */
1168 public DisconnectHandler getDisconnectHandler()
1169 {
1170 return disconnectHandler;
1171 }
1172
1173
1174
1175 /**
1176 * Specifies the disconnect handler to use for associated connections.
1177 *
1178 * @param handler The disconnect handler to use for associated connections.
1179 */
1180 public void setDisconnectHandler(final DisconnectHandler handler)
1181 {
1182 disconnectHandler = handler;
1183 }
1184
1185
1186
1187 /**
1188 * Retrieves the unsolicited notification handler to use for associated
1189 * connections.
1190 *
1191 * @return The unsolicited notification handler to use for associated
1192 * connections, or {@code null} if none is defined.
1193 */
1194 public UnsolicitedNotificationHandler getUnsolicitedNotificationHandler()
1195 {
1196 return unsolicitedNotificationHandler;
1197 }
1198
1199
1200
1201 /**
1202 * Specifies the unsolicited notification handler to use for associated
1203 * connections.
1204 *
1205 * @param handler The unsolicited notification handler to use for associated
1206 * connections.
1207 */
1208 public void setUnsolicitedNotificationHandler(
1209 final UnsolicitedNotificationHandler handler)
1210 {
1211 unsolicitedNotificationHandler = handler;
1212 }
1213
1214
1215
1216 /**
1217 * Retrieves the socket receive buffer size that should be requested when
1218 * establishing a connection.
1219 *
1220 * @return The socket receive buffer size that should be requested when
1221 * establishing a connection, or zero if the default size should be
1222 * used.
1223 */
1224 public int getReceiveBufferSize()
1225 {
1226 return receiveBufferSize;
1227 }
1228
1229
1230
1231 /**
1232 * Specifies the socket receive buffer size that should be requested when
1233 * establishing a connection.
1234 *
1235 * @param receiveBufferSize The socket receive buffer size that should be
1236 * requested when establishing a connection, or
1237 * zero if the default size should be used.
1238 */
1239 public void setReceiveBufferSize(final int receiveBufferSize)
1240 {
1241 if (receiveBufferSize < 0)
1242 {
1243 this.receiveBufferSize = 0;
1244 }
1245 else
1246 {
1247 this.receiveBufferSize = receiveBufferSize;
1248 }
1249 }
1250
1251
1252
1253 /**
1254 * Retrieves the socket send buffer size that should be requested when
1255 * establishing a connection.
1256 *
1257 * @return The socket send buffer size that should be requested when
1258 * establishing a connection, or zero if the default size should be
1259 * used.
1260 */
1261 public int getSendBufferSize()
1262 {
1263 return sendBufferSize;
1264 }
1265
1266
1267
1268 /**
1269 * Specifies the socket send buffer size that should be requested when
1270 * establishing a connection.
1271 *
1272 * @param sendBufferSize The socket send buffer size that should be
1273 * requested when establishing a connection, or zero
1274 * if the default size should be used.
1275 */
1276 public void setSendBufferSize(final int sendBufferSize)
1277 {
1278 if (sendBufferSize < 0)
1279 {
1280 this.sendBufferSize = 0;
1281 }
1282 else
1283 {
1284 this.sendBufferSize = sendBufferSize;
1285 }
1286 }
1287
1288
1289
1290 /**
1291 * Indicates whether to allow a socket factory instance (which may be shared
1292 * across multiple connections) to be used create multiple sockets
1293 * concurrently. In general, socket factory implementations are threadsafe
1294 * and can be to create multiple connections simultaneously across separate
1295 * threads, but this is known to not be the case in some VM implementations
1296 * (e.g., SSL socket factories in IBM JVMs). This setting may be used to
1297 * indicate whether concurrent socket creation attempts should be allowed
1298 * (which may allow for better and more consistent performance, especially in
1299 * cases where a connection attempt fails due to a timeout) or prevented
1300 * (which may be necessary for non-threadsafe socket factory implementations).
1301 *
1302 * @return {@code true} if multiple threads should be able to concurrently
1303 * use the same socket factory instance, or {@code false} if Java
1304 * synchronization should be used to ensure that no more than one
1305 * thread is allowed to use a socket factory at any given time.
1306 */
1307 public boolean allowConcurrentSocketFactoryUse()
1308 {
1309 return allowConcurrentSocketFactoryUse;
1310 }
1311
1312
1313
1314 /**
1315 * Specifies whether to allow a socket factory instance (which may be shared
1316 * across multiple connections) to be used create multiple sockets
1317 * concurrently. In general, socket factory implementations are threadsafe
1318 * and can be to create multiple connections simultaneously across separate
1319 * threads, but this is known to not be the case in some VM implementations
1320 * (e.g., SSL socket factories in IBM JVMs). This setting may be used to
1321 * indicate whether concurrent socket creation attempts should be allowed
1322 * (which may allow for better and more consistent performance, especially in
1323 * cases where a connection attempt fails due to a timeout) or prevented
1324 * (which may be necessary for non-threadsafe socket factory implementations).
1325 *
1326 * @param allowConcurrentSocketFactoryUse Indicates whether to allow a
1327 * socket factory instance to be used
1328 * to create multiple sockets
1329 * concurrently.
1330 */
1331 public void setAllowConcurrentSocketFactoryUse(
1332 final boolean allowConcurrentSocketFactoryUse)
1333 {
1334 this.allowConcurrentSocketFactoryUse = allowConcurrentSocketFactoryUse;
1335 }
1336
1337
1338
1339 /**
1340 * Retrieves the {@code SSLSocketVerifier} that will be used to perform
1341 * additional validation for any newly-created {@code SSLSocket} instances.
1342 *
1343 * @return The {@code SSLSocketVerifier} that will be used to perform
1344 * additional validation for any newly-created {@code SSLSocket}
1345 * instances.
1346 */
1347 public SSLSocketVerifier getSSLSocketVerifier()
1348 {
1349 return sslSocketVerifier;
1350 }
1351
1352
1353
1354 /**
1355 * Specifies the {@code SSLSocketVerifier} that will be used to perform
1356 * additional validation for any newly-created {@code SSLSocket} instances.
1357 *
1358 * @param sslSocketVerifier The {@code SSLSocketVerifier} that will be used
1359 * to perform additional validation for any
1360 * newly-created {@code SSLSocket} instances.
1361 */
1362 public void setSSLSocketVerifier(final SSLSocketVerifier sslSocketVerifier)
1363 {
1364 if (sslSocketVerifier == null)
1365 {
1366 this.sslSocketVerifier = DEFAULT_SSL_SOCKET_VERIFIER;
1367 }
1368 else
1369 {
1370 this.sslSocketVerifier = sslSocketVerifier;
1371 }
1372 }
1373
1374
1375
1376 /**
1377 * Retrieves a string representation of this LDAP connection.
1378 *
1379 * @return A string representation of this LDAP connection.
1380 */
1381 @Override()
1382 public String toString()
1383 {
1384 final StringBuilder buffer = new StringBuilder();
1385 toString(buffer);
1386 return buffer.toString();
1387 }
1388
1389
1390
1391 /**
1392 * Appends a string representation of this LDAP connection to the provided
1393 * buffer.
1394 *
1395 * @param buffer The buffer to which to append a string representation of
1396 * this LDAP connection.
1397 */
1398 public void toString(final StringBuilder buffer)
1399 {
1400 buffer.append("LDAPConnectionOptions(autoReconnect=");
1401 buffer.append(autoReconnect);
1402 buffer.append(", bindWithDNRequiresPassword=");
1403 buffer.append(bindWithDNRequiresPassword);
1404 buffer.append(", followReferrals=");
1405 buffer.append(followReferrals);
1406 if (followReferrals)
1407 {
1408 buffer.append(", referralHopLimit=");
1409 buffer.append(referralHopLimit);
1410 }
1411 if (referralConnector != null)
1412 {
1413 buffer.append(", referralConnectorClass=");
1414 buffer.append(referralConnector.getClass().getName());
1415 }
1416 buffer.append(", useKeepAlive=");
1417 buffer.append(useKeepAlive);
1418 buffer.append(", useLinger=");
1419 if (useLinger)
1420 {
1421 buffer.append("true, lingerTimeoutSeconds=");
1422 buffer.append(lingerTimeout);
1423 }
1424 else
1425 {
1426 buffer.append("false");
1427 }
1428 buffer.append(", useReuseAddress=");
1429 buffer.append(useReuseAddress);
1430 buffer.append(", useSchema=");
1431 buffer.append(useSchema);
1432 buffer.append(", usePooledSchema=");
1433 buffer.append(usePooledSchema);
1434 buffer.append(", pooledSchemaTimeoutMillis=");
1435 buffer.append(pooledSchemaTimeout);
1436 buffer.append(", useSynchronousMode=");
1437 buffer.append(useSynchronousMode);
1438 buffer.append(", useTCPNoDelay=");
1439 buffer.append(useTCPNoDelay);
1440 buffer.append(", captureConnectStackTrace=");
1441 buffer.append(captureConnectStackTrace);
1442 buffer.append(", connectTimeoutMillis=");
1443 buffer.append(connectTimeout);
1444 buffer.append(", responseTimeoutMillis=");
1445 buffer.append(responseTimeout);
1446 buffer.append(", abandonOnTimeout=");
1447 buffer.append(abandonOnTimeout);
1448 buffer.append(", maxMessageSize=");
1449 buffer.append(maxMessageSize);
1450 buffer.append(", receiveBufferSize=");
1451 buffer.append(receiveBufferSize);
1452 buffer.append(", sendBufferSize=");
1453 buffer.append(sendBufferSize);
1454 buffer.append(", allowConcurrentSocketFactoryUse=");
1455 buffer.append(allowConcurrentSocketFactoryUse);
1456 if (disconnectHandler != null)
1457 {
1458 buffer.append(", disconnectHandlerClass=");
1459 buffer.append(disconnectHandler.getClass().getName());
1460 }
1461 if (unsolicitedNotificationHandler != null)
1462 {
1463 buffer.append(", unsolicitedNotificationHandlerClass=");
1464 buffer.append(unsolicitedNotificationHandler.getClass().getName());
1465 }
1466
1467 buffer.append(", sslSocketVerifierClass='");
1468 buffer.append(sslSocketVerifier.getClass().getName());
1469 buffer.append('\'');
1470
1471 buffer.append(')');
1472 }
1473 }