001 /*
002 * Copyright 2007-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 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 java.io.Closeable;
026 import java.net.InetAddress;
027 import java.net.Socket;
028 import java.util.Collection;
029 import java.util.HashMap;
030 import java.util.List;
031 import java.util.Map;
032 import java.util.Timer;
033 import java.util.concurrent.atomic.AtomicBoolean;
034 import java.util.concurrent.atomic.AtomicLong;
035 import java.util.concurrent.atomic.AtomicReference;
036 import java.util.logging.Level;
037 import javax.net.SocketFactory;
038 import javax.net.ssl.SSLSession;
039 import javax.net.ssl.SSLSocket;
040 import javax.net.ssl.SSLSocketFactory;
041 import javax.security.sasl.SaslClient;
042
043 import com.unboundid.asn1.ASN1OctetString;
044 import com.unboundid.ldap.protocol.AbandonRequestProtocolOp;
045 import com.unboundid.ldap.protocol.LDAPMessage;
046 import com.unboundid.ldap.protocol.LDAPResponse;
047 import com.unboundid.ldap.protocol.UnbindRequestProtocolOp;
048 import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
049 import com.unboundid.ldap.sdk.schema.Schema;
050 import com.unboundid.ldif.LDIFException;
051 import com.unboundid.util.DebugType;
052 import com.unboundid.util.SynchronizedSocketFactory;
053 import com.unboundid.util.SynchronizedSSLSocketFactory;
054 import com.unboundid.util.ThreadSafety;
055 import com.unboundid.util.ThreadSafetyLevel;
056 import com.unboundid.util.WeakHashSet;
057
058 import static com.unboundid.ldap.sdk.LDAPMessages.*;
059 import static com.unboundid.util.Debug.*;
060 import static com.unboundid.util.StaticUtils.*;
061 import static com.unboundid.util.Validator.*;
062
063
064
065 /**
066 * This class provides a facility for interacting with an LDAPv3 directory
067 * server. It provides a means of establishing a connection to the server,
068 * sending requests, and reading responses. See
069 * <A HREF="http://www.ietf.org/rfc/rfc4511.txt">RFC 4511</A> for the LDAPv3
070 * protocol specification and more information about the types of operations
071 * defined in LDAP.
072 * <BR><BR>
073 * <H2>Creating, Establishing, and Authenticating Connections</H2>
074 * An LDAP connection can be established either at the time that the object is
075 * created or as a separate step. Similarly, authentication can be performed on
076 * the connection at the time it is created, at the time it is established, or
077 * as a separate process. For example:
078 * <BR><BR>
079 * <PRE>
080 * // Create a new, unestablished connection. Then connect and perform a
081 * // simple bind as separate operations.
082 * LDAPConnection c = new LDAPConnection();
083 * c.connect(address, port);
084 * BindResult bindResult = c.bind(bindDN, password);
085 *
086 * // Create a new connection that is established at creation time, and then
087 * // authenticate separately using simple authentication.
088 * LDAPConnection c = new LDAPConnection(address, port);
089 * BindResult bindResult = c.bind(bindDN, password);
090 *
091 * // Create a new connection that is established and bound using simple
092 * // authentication all in one step.
093 * LDAPConnection c = new LDAPConnection(address, port, bindDN, password);
094 * </PRE>
095 * <BR><BR>
096 * When authentication is performed at the time that the connection is
097 * established, it is only possible to perform a simple bind and it is not
098 * possible to include controls in the bind request, nor is it possible to
099 * receive response controls if the bind was successful. Therefore, it is
100 * recommended that authentication be performed as a separate step if the server
101 * may return response controls even in the event of a successful authentication
102 * (e.g., a control that may indicate that the user's password will soon
103 * expire). See the {@link BindRequest} class for more information about
104 * authentication in the UnboundID LDAP SDK for Java.
105 * <BR><BR>
106 * By default, connections will use standard unencrypted network sockets.
107 * However, it may be desirable to create connections that use SSL/TLS to
108 * encrypt communication. This can be done by specifying a
109 * {@link javax.net.SocketFactory} that should be used to create the socket to
110 * use to communicate with the directory server. The
111 * {@link javax.net.ssl.SSLSocketFactory#getDefault} method or the
112 * {@link javax.net.ssl.SSLContext#getSocketFactory} method may be used to
113 * obtain a socket factory for performing SSL communication. See the
114 * <A HREF=
115 * "http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html">
116 * JSSE Reference Guide</A> for more information on using these classes.
117 * Alternately, you may use the {@link com.unboundid.util.ssl.SSLUtil} class to
118 * simplify the process.
119 * <BR><BR>
120 * Whenever the connection is no longer needed, it may be terminated using the
121 * {@link LDAPConnection#close} method.
122 * <BR><BR>
123 * <H2>Processing LDAP Operations</H2>
124 * This class provides a number of methods for processing the different types of
125 * operations. The types of operations that can be processed include:
126 * <UL>
127 * <LI>Abandon -- This may be used to request that the server stop processing
128 * on an operation that has been invoked asynchronously.</LI>
129 * <LI>Add -- This may be used to add a new entry to the directory
130 * server. See the {@link AddRequest} class for more information about
131 * processing add operations.</LI>
132 * <LI>Bind -- This may be used to authenticate to the directory server. See
133 * the {@link BindRequest} class for more information about processing
134 * bind operations.</LI>
135 * <LI>Compare -- This may be used to determine whether a specified entry has
136 * a given attribute value. See the {@link CompareRequest} class for more
137 * information about processing compare operations.</LI>
138 * <LI>Delete -- This may be used to remove an entry from the directory
139 * server. See the {@link DeleteRequest} class for more information about
140 * processing delete operations.</LI>
141 * <LI>Extended -- This may be used to process an operation which is not
142 * part of the core LDAP protocol but is a custom extension supported by
143 * the directory server. See the {@link ExtendedRequest} class for more
144 * information about processing extended operations.</LI>
145 * <LI>Modify -- This may be used to alter an entry in the directory
146 * server. See the {@link ModifyRequest} class for more information about
147 * processing modify operations.</LI>
148 * <LI>Modify DN -- This may be used to rename an entry or subtree and/or move
149 * that entry or subtree below a new parent in the directory server. See
150 * the {@link ModifyDNRequest} class for more information about processing
151 * modify DN operations.</LI>
152 * <LI>Search -- This may be used to retrieve a set of entries in the server
153 * that match a given set of criteria. See the {@link SearchRequest}
154 * class for more information about processing search operations.</LI>
155 * </UL>
156 * <BR><BR>
157 * Most of the methods in this class used to process operations operate in a
158 * synchronous manner. In these cases, the SDK will send a request to the
159 * server and wait for a response to arrive before returning to the caller. In
160 * these cases, the value returned will include the contents of that response,
161 * including the result code, diagnostic message, matched DN, referral URLs, and
162 * any controls that may have been included. However, it also possible to
163 * process operations asynchronously, in which case the SDK will return control
164 * back to the caller after the request has been sent to the server but before
165 * the response has been received. In this case, the SDK will return an
166 * {@link AsyncRequestID} object which may be used to later abandon or cancel
167 * that operation if necessary, and will notify the client when the response
168 * arrives via a listener interface.
169 * <BR><BR>
170 * This class is mostly threadsafe. It is possible to process multiple
171 * concurrent operations over the same connection as long as the methods being
172 * invoked will not change the state of the connection in a way that might
173 * impact other operations in progress in unexpected ways. In particular, the
174 * following should not be attempted while any other operations may be in
175 * progress on this connection:
176 * <UL>
177 * <LI>
178 * Using one of the {@code connect} methods to re-establish the connection.
179 * </LI>
180 * <LI>
181 * Using one of the {@code close} methods to terminate the connection.
182 * </LI>
183 * <LI>
184 * Using one of the {@code bind} methods to attempt to authenticate the
185 * connection (unless you are certain that the bind will not impact the
186 * identity of the associated connection, for example by including the
187 * retain identity request control in the bind request if using the
188 * Commercial Edition of the LDAP SDK in conjunction with a Ping Identity,
189 * UnboundID, or Alcatel-Lucent 8661 Directory Server).
190 * </LI>
191 * <LI>
192 * Attempting to make a change to the way that the underlying communication
193 * is processed (e.g., by using the StartTLS extended operation to convert
194 * an insecure connection into a secure one).
195 * </LI>
196 * </UL>
197 */
198 @ThreadSafety(level=ThreadSafetyLevel.MOSTLY_THREADSAFE)
199 public final class LDAPConnection
200 implements LDAPInterface, ReferralConnector, Closeable
201 {
202 /**
203 * The counter that will be used when assigning connection IDs to connections.
204 */
205 private static final AtomicLong NEXT_CONNECTION_ID = new AtomicLong(0L);
206
207
208
209 /**
210 * The default socket factory that will be used if no alternate factory is
211 * provided.
212 */
213 private static final SocketFactory DEFAULT_SOCKET_FACTORY =
214 SocketFactory.getDefault();
215
216
217
218 /**
219 * A set of weak references to schema objects that can be shared across
220 * connections if they are identical.
221 */
222 private static final WeakHashSet<Schema> SCHEMA_SET =
223 new WeakHashSet<Schema>();
224
225
226
227 // The connection pool with which this connection is associated, if
228 // applicable.
229 private AbstractConnectionPool connectionPool;
230
231 // Indicates whether to perform a reconnect before the next write.
232 private final AtomicBoolean needsReconnect;
233
234 // The disconnect information for this connection.
235 private final AtomicReference<DisconnectInfo> disconnectInfo;
236
237 // The last successful bind request processed on this connection.
238 private volatile BindRequest lastBindRequest;
239
240 // Indicates whether a request has been made to close this connection.
241 private volatile boolean closeRequested;
242
243 // Indicates whether an unbind request has been sent over this connection.
244 private volatile boolean unbindRequestSent;
245
246 // The extended request used to initiate StartTLS on this connection.
247 private volatile ExtendedRequest startTLSRequest;
248
249 // The port of the server to which a connection should be re-established.
250 private int reconnectPort = -1;
251
252 // The connection internals used to actually perform the network
253 // communication.
254 private volatile LDAPConnectionInternals connectionInternals;
255
256 // The set of connection options for this connection.
257 private LDAPConnectionOptions connectionOptions;
258
259 // The set of statistics for this connection.
260 private final LDAPConnectionStatistics connectionStatistics;
261
262 // The unique identifier assigned to this connection when it was created. It
263 // will not change over the life of the connection, even if the connection is
264 // closed and re-established (or even re-established to a different server).
265 private final long connectionID;
266
267 // The time of the last rebind attempt.
268 private long lastReconnectTime;
269
270 // The most recent time that an LDAP message was sent or received on this
271 // connection.
272 private volatile long lastCommunicationTime;
273
274 // A map in which arbitrary attachments may be stored or managed.
275 private Map<String,Object> attachments;
276
277 // The referral connector that will be used to establish connections to remote
278 // servers when following a referral.
279 private volatile ReferralConnector referralConnector;
280
281 // The cached schema read from the server.
282 private volatile Schema cachedSchema;
283
284 // The socket factory used for the last connection attempt.
285 private SocketFactory lastUsedSocketFactory;
286
287 // The socket factory used to create sockets for subsequent connection
288 // attempts.
289 private volatile SocketFactory socketFactory;
290
291 // A stack trace of the thread that last established this connection.
292 private StackTraceElement[] connectStackTrace;
293
294 // The user-friendly name assigned to this connection.
295 private String connectionName;
296
297 // The user-friendly name assigned to the connection pool with which this
298 // connection is associated.
299 private String connectionPoolName;
300
301 // A string representation of the host and port to which the last connection
302 // attempt (whether successful or not, and whether it is still established)
303 // was made.
304 private String hostPort;
305
306 // The address of the server to which a connection should be re-established.
307 private String reconnectAddress;
308
309 // A timer that may be used to enforce timeouts for asynchronous operations.
310 private Timer timer;
311
312
313
314 /**
315 * Creates a new LDAP connection using the default socket factory and default
316 * set of connection options. No actual network connection will be
317 * established.
318 */
319 public LDAPConnection()
320 {
321 this(null, null);
322 }
323
324
325
326 /**
327 * Creates a new LDAP connection using the default socket factory and provided
328 * set of connection options. No actual network connection will be
329 * established.
330 *
331 * @param connectionOptions The set of connection options to use for this
332 * connection. If it is {@code null}, then a
333 * default set of options will be used.
334 */
335 public LDAPConnection(final LDAPConnectionOptions connectionOptions)
336 {
337 this(null, connectionOptions);
338 }
339
340
341
342 /**
343 * Creates a new LDAP connection using the specified socket factory. No
344 * actual network connection will be established.
345 *
346 * @param socketFactory The socket factory to use when establishing
347 * connections. If it is {@code null}, then a default
348 * socket factory will be used.
349 */
350 public LDAPConnection(final SocketFactory socketFactory)
351 {
352 this(socketFactory, null);
353 }
354
355
356
357 /**
358 * Creates a new LDAP connection using the specified socket factory. No
359 * actual network connection will be established.
360 *
361 * @param socketFactory The socket factory to use when establishing
362 * connections. If it is {@code null}, then a
363 * default socket factory will be used.
364 * @param connectionOptions The set of connection options to use for this
365 * connection. If it is {@code null}, then a
366 * default set of options will be used.
367 */
368 public LDAPConnection(final SocketFactory socketFactory,
369 final LDAPConnectionOptions connectionOptions)
370 {
371 needsReconnect = new AtomicBoolean(false);
372 disconnectInfo = new AtomicReference<DisconnectInfo>();
373 lastCommunicationTime = -1L;
374
375 connectionID = NEXT_CONNECTION_ID.getAndIncrement();
376
377 if (connectionOptions == null)
378 {
379 this.connectionOptions = new LDAPConnectionOptions();
380 }
381 else
382 {
383 this.connectionOptions = connectionOptions.duplicate();
384 }
385
386 final SocketFactory f;
387 if (socketFactory == null)
388 {
389 f = DEFAULT_SOCKET_FACTORY;
390 }
391 else
392 {
393 f = socketFactory;
394 }
395
396 if (this.connectionOptions.allowConcurrentSocketFactoryUse())
397 {
398 this.socketFactory = f;
399 }
400 else
401 {
402 if (f instanceof SSLSocketFactory)
403 {
404 this.socketFactory =
405 new SynchronizedSSLSocketFactory((SSLSocketFactory) f);
406 }
407 else
408 {
409 this.socketFactory = new SynchronizedSocketFactory(f);
410 }
411 }
412
413 attachments = null;
414 connectionStatistics = new LDAPConnectionStatistics();
415 connectionName = null;
416 connectionPoolName = null;
417 cachedSchema = null;
418 timer = null;
419
420 referralConnector = this.connectionOptions.getReferralConnector();
421 if (referralConnector == null)
422 {
423 referralConnector = this;
424 }
425 }
426
427
428
429 /**
430 * Creates a new, unauthenticated LDAP connection that is established to the
431 * specified server.
432 *
433 * @param host The string representation of the address of the server to
434 * which the connection should be established. It may be a
435 * resolvable name or an IP address. It must not be
436 * {@code null}.
437 * @param port The port number of the server to which the connection should
438 * be established. It should be a value between 1 and 65535,
439 * inclusive.
440 *
441 * @throws LDAPException If a problem occurs while attempting to connect to
442 * the specified server.
443 */
444 public LDAPConnection(final String host, final int port)
445 throws LDAPException
446 {
447 this(null, null, host, port);
448 }
449
450
451
452 /**
453 * Creates a new, unauthenticated LDAP connection that is established to the
454 * specified server.
455 *
456 * @param connectionOptions The set of connection options to use for this
457 * connection. If it is {@code null}, then a
458 * default set of options will be used.
459 * @param host The string representation of the address of the
460 * server to which the connection should be
461 * established. It may be a resolvable name or an
462 * IP address. It must not be {@code null}.
463 * @param port The port number of the server to which the
464 * connection should be established. It should be
465 * a value between 1 and 65535, inclusive.
466 *
467 * @throws LDAPException If a problem occurs while attempting to connect to
468 * the specified server.
469 */
470 public LDAPConnection(final LDAPConnectionOptions connectionOptions,
471 final String host, final int port)
472 throws LDAPException
473 {
474 this(null, connectionOptions, host, port);
475 }
476
477
478
479 /**
480 * Creates a new, unauthenticated LDAP connection that is established to the
481 * specified server.
482 *
483 * @param socketFactory The socket factory to use when establishing
484 * connections. If it is {@code null}, then a default
485 * socket factory will be used.
486 * @param host The string representation of the address of the
487 * server to which the connection should be
488 * established. It may be a resolvable name or an IP
489 * address. It must not be {@code null}.
490 * @param port The port number of the server to which the
491 * connection should be established. It should be a
492 * value between 1 and 65535, inclusive.
493 *
494 * @throws LDAPException If a problem occurs while attempting to connect to
495 * the specified server.
496 */
497 public LDAPConnection(final SocketFactory socketFactory, final String host,
498 final int port)
499 throws LDAPException
500 {
501 this(socketFactory, null, host, port);
502 }
503
504
505
506 /**
507 * Creates a new, unauthenticated LDAP connection that is established to the
508 * specified server.
509 *
510 * @param socketFactory The socket factory to use when establishing
511 * connections. If it is {@code null}, then a
512 * default socket factory will be used.
513 * @param connectionOptions The set of connection options to use for this
514 * connection. If it is {@code null}, then a
515 * default set of options will be used.
516 * @param host The string representation of the address of the
517 * server to which the connection should be
518 * established. It may be a resolvable name or an
519 * IP address. It must not be {@code null}.
520 * @param port The port number of the server to which the
521 * connection should be established. It should be
522 * a value between 1 and 65535, inclusive.
523 *
524 * @throws LDAPException If a problem occurs while attempting to connect to
525 * the specified server.
526 */
527 public LDAPConnection(final SocketFactory socketFactory,
528 final LDAPConnectionOptions connectionOptions,
529 final String host, final int port)
530 throws LDAPException
531 {
532 this(socketFactory, connectionOptions);
533
534 connect(host, port);
535 }
536
537
538
539 /**
540 * Creates a new LDAP connection that is established to the specified server
541 * and is authenticated as the specified user (via LDAP simple
542 * authentication).
543 *
544 * @param host The string representation of the address of the
545 * server to which the connection should be established.
546 * It may be a resolvable name or an IP address. It
547 * must not be {@code null}.
548 * @param port The port number of the server to which the
549 * connection should be established. It should be a
550 * value between 1 and 65535, inclusive.
551 * @param bindDN The DN to use to authenticate to the directory
552 * server.
553 * @param bindPassword The password to use to authenticate to the directory
554 * server.
555 *
556 * @throws LDAPException If a problem occurs while attempting to connect to
557 * the specified server.
558 */
559 public LDAPConnection(final String host, final int port, final String bindDN,
560 final String bindPassword)
561 throws LDAPException
562 {
563 this(null, null, host, port, bindDN, bindPassword);
564 }
565
566
567
568 /**
569 * Creates a new LDAP connection that is established to the specified server
570 * and is authenticated as the specified user (via LDAP simple
571 * authentication).
572 *
573 * @param connectionOptions The set of connection options to use for this
574 * connection. If it is {@code null}, then a
575 * default set of options will be used.
576 * @param host The string representation of the address of the
577 * server to which the connection should be
578 * established. It may be a resolvable name or an
579 * IP address. It must not be {@code null}.
580 * @param port The port number of the server to which the
581 * connection should be established. It should be
582 * a value between 1 and 65535, inclusive.
583 * @param bindDN The DN to use to authenticate to the directory
584 * server.
585 * @param bindPassword The password to use to authenticate to the
586 * directory server.
587 *
588 * @throws LDAPException If a problem occurs while attempting to connect to
589 * the specified server.
590 */
591 public LDAPConnection(final LDAPConnectionOptions connectionOptions,
592 final String host, final int port, final String bindDN,
593 final String bindPassword)
594 throws LDAPException
595 {
596 this(null, connectionOptions, host, port, bindDN, bindPassword);
597 }
598
599
600
601 /**
602 * Creates a new LDAP connection that is established to the specified server
603 * and is authenticated as the specified user (via LDAP simple
604 * authentication).
605 *
606 * @param socketFactory The socket factory to use when establishing
607 * connections. If it is {@code null}, then a default
608 * socket factory will be used.
609 * @param host The string representation of the address of the
610 * server to which the connection should be
611 * established. It may be a resolvable name or an IP
612 * address. It must not be {@code null}.
613 * @param port The port number of the server to which the
614 * connection should be established. It should be a
615 * value between 1 and 65535, inclusive.
616 * @param bindDN The DN to use to authenticate to the directory
617 * server.
618 * @param bindPassword The password to use to authenticate to the directory
619 * server.
620 *
621 * @throws LDAPException If a problem occurs while attempting to connect to
622 * the specified server.
623 */
624 public LDAPConnection(final SocketFactory socketFactory, final String host,
625 final int port, final String bindDN,
626 final String bindPassword)
627 throws LDAPException
628 {
629 this(socketFactory, null, host, port, bindDN, bindPassword);
630 }
631
632
633
634 /**
635 * Creates a new LDAP connection that is established to the specified server
636 * and is authenticated as the specified user (via LDAP simple
637 * authentication).
638 *
639 * @param socketFactory The socket factory to use when establishing
640 * connections. If it is {@code null}, then a
641 * default socket factory will be used.
642 * @param connectionOptions The set of connection options to use for this
643 * connection. If it is {@code null}, then a
644 * default set of options will be used.
645 * @param host The string representation of the address of the
646 * server to which the connection should be
647 * established. It may be a resolvable name or an
648 * IP address. It must not be {@code null}.
649 * @param port The port number of the server to which the
650 * connection should be established. It should be
651 * a value between 1 and 65535, inclusive.
652 * @param bindDN The DN to use to authenticate to the directory
653 * server.
654 * @param bindPassword The password to use to authenticate to the
655 * directory server.
656 *
657 * @throws LDAPException If a problem occurs while attempting to connect to
658 * the specified server.
659 */
660 public LDAPConnection(final SocketFactory socketFactory,
661 final LDAPConnectionOptions connectionOptions,
662 final String host, final int port, final String bindDN,
663 final String bindPassword)
664 throws LDAPException
665 {
666 this(socketFactory, connectionOptions, host, port);
667
668 try
669 {
670 bind(new SimpleBindRequest(bindDN, bindPassword));
671 }
672 catch (LDAPException le)
673 {
674 debugException(le);
675 setDisconnectInfo(DisconnectType.BIND_FAILED, null, le);
676 close();
677 throw le;
678 }
679 }
680
681
682
683 /**
684 * Establishes an unauthenticated connection to the directory server using the
685 * provided information. If the connection is already established, then it
686 * will be closed and re-established.
687 * <BR><BR>
688 * If this method is invoked while any operations are in progress on this
689 * connection, then the directory server may or may not abort processing for
690 * those operations, depending on the type of operation and how far along the
691 * server has already gotten while processing that operation. It is
692 * recommended that all active operations be abandoned, canceled, or allowed
693 * to complete before attempting to re-establish an active connection.
694 *
695 * @param host The string representation of the address of the server to
696 * which the connection should be established. It may be a
697 * resolvable name or an IP address. It must not be
698 * {@code null}.
699 * @param port The port number of the server to which the connection should
700 * be established. It should be a value between 1 and 65535,
701 * inclusive.
702 *
703 * @throws LDAPException If an error occurs while attempting to establish
704 * the connection.
705 */
706 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
707 public void connect(final String host, final int port)
708 throws LDAPException
709 {
710 connect(host, port, connectionOptions.getConnectTimeoutMillis());
711 }
712
713
714
715 /**
716 * Establishes an unauthenticated connection to the directory server using the
717 * provided information. If the connection is already established, then it
718 * will be closed and re-established.
719 * <BR><BR>
720 * If this method is invoked while any operations are in progress on this
721 * connection, then the directory server may or may not abort processing for
722 * those operations, depending on the type of operation and how far along the
723 * server has already gotten while processing that operation. It is
724 * recommended that all active operations be abandoned, canceled, or allowed
725 * to complete before attempting to re-establish an active connection.
726 *
727 * @param host The string representation of the address of the server to
728 * which the connection should be established. It may be a
729 * resolvable name or an IP address. It must not be
730 * {@code null}.
731 * @param port The port number of the server to which the connection
732 * should be established. It should be a value between 1 and
733 * 65535, inclusive.
734 * @param timeout The maximum length of time in milliseconds to wait for the
735 * connection to be established before failing, or zero to
736 * indicate that no timeout should be enforced (although if
737 * the attempt stalls long enough, then the underlying
738 * operating system may cause it to timeout).
739 *
740 * @throws LDAPException If an error occurs while attempting to establish
741 * the connection.
742 */
743 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
744 public void connect(final String host, final int port, final int timeout)
745 throws LDAPException
746 {
747 final InetAddress inetAddress;
748 try
749 {
750 inetAddress = InetAddress.getByName(host);
751 }
752 catch (final Exception e)
753 {
754 debugException(e);
755 throw new LDAPException(ResultCode.CONNECT_ERROR,
756 ERR_CONN_RESOLVE_ERROR.get(host, getExceptionMessage(e)),
757 e);
758 }
759
760 connect(host, inetAddress, port, timeout);
761 }
762
763
764
765 /**
766 * Establishes an unauthenticated connection to the directory server using the
767 * provided information. If the connection is already established, then it
768 * will be closed and re-established.
769 * <BR><BR>
770 * If this method is invoked while any operations are in progress on this
771 * connection, then the directory server may or may not abort processing for
772 * those operations, depending on the type of operation and how far along the
773 * server has already gotten while processing that operation. It is
774 * recommended that all active operations be abandoned, canceled, or allowed
775 * to complete before attempting to re-establish an active connection.
776 *
777 * @param inetAddress The inet address of the server to which the connection
778 * should be established. It must not be {@code null}.
779 * @param port The port number of the server to which the connection
780 * should be established. It should be a value between 1
781 * and 65535, inclusive.
782 * @param timeout The maximum length of time in milliseconds to wait for
783 * the connection to be established before failing, or
784 * zero to indicate that no timeout should be enforced
785 * (although if the attempt stalls long enough, then the
786 * underlying operating system may cause it to timeout).
787 *
788 * @throws LDAPException If an error occurs while attempting to establish
789 * the connection.
790 */
791 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
792 public void connect(final InetAddress inetAddress, final int port,
793 final int timeout)
794 throws LDAPException
795 {
796 connect(inetAddress.getHostName(), inetAddress, port, timeout);
797 }
798
799
800
801 /**
802 * Establishes an unauthenticated connection to the directory server using the
803 * provided information. If the connection is already established, then it
804 * will be closed and re-established.
805 * <BR><BR>
806 * If this method is invoked while any operations are in progress on this
807 * connection, then the directory server may or may not abort processing for
808 * those operations, depending on the type of operation and how far along the
809 * server has already gotten while processing that operation. It is
810 * recommended that all active operations be abandoned, canceled, or allowed
811 * to complete before attempting to re-establish an active connection.
812 *
813 * @param host The string representation of the address of the server
814 * to which the connection should be established. It may
815 * be a resolvable name or an IP address. It must not be
816 * {@code null}.
817 * @param inetAddress The inet address of the server to which the connection
818 * should be established. It must not be {@code null}.
819 * @param port The port number of the server to which the connection
820 * should be established. It should be a value between 1
821 * and 65535, inclusive.
822 * @param timeout The maximum length of time in milliseconds to wait for
823 * the connection to be established before failing, or
824 * zero to indicate that no timeout should be enforced
825 * (although if the attempt stalls long enough, then the
826 * underlying operating system may cause it to timeout).
827 *
828 * @throws LDAPException If an error occurs while attempting to establish
829 * the connection.
830 */
831 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
832 public void connect(final String host, final InetAddress inetAddress,
833 final int port, final int timeout)
834 throws LDAPException
835 {
836 ensureNotNull(host, inetAddress, port);
837
838 needsReconnect.set(false);
839 hostPort = host + ':' + port;
840 lastCommunicationTime = -1L;
841 startTLSRequest = null;
842
843 if (isConnected())
844 {
845 setDisconnectInfo(DisconnectType.RECONNECT, null, null);
846 close();
847 }
848
849 lastUsedSocketFactory = socketFactory;
850 reconnectAddress = host;
851 reconnectPort = port;
852 cachedSchema = null;
853 unbindRequestSent = false;
854
855 disconnectInfo.set(null);
856
857 try
858 {
859 connectionStatistics.incrementNumConnects();
860 connectionInternals = new LDAPConnectionInternals(this, connectionOptions,
861 lastUsedSocketFactory, host, inetAddress, port, timeout);
862 connectionInternals.startConnectionReader();
863 lastCommunicationTime = System.currentTimeMillis();
864 }
865 catch (Exception e)
866 {
867 debugException(e);
868 setDisconnectInfo(DisconnectType.LOCAL_ERROR, null, e);
869 connectionInternals = null;
870 throw new LDAPException(ResultCode.CONNECT_ERROR,
871 ERR_CONN_CONNECT_ERROR.get(getHostPort(), String.valueOf(e)), e);
872 }
873
874 if (connectionOptions.useSchema())
875 {
876 try
877 {
878 cachedSchema = getCachedSchema(this);
879 }
880 catch (Exception e)
881 {
882 debugException(e);
883 }
884 }
885 }
886
887
888
889 /**
890 * Attempts to re-establish a connection to the server and re-authenticate if
891 * appropriate.
892 *
893 * @throws LDAPException If a problem occurs while attempting to re-connect
894 * or re-authenticate.
895 */
896 public void reconnect()
897 throws LDAPException
898 {
899 needsReconnect.set(false);
900 if ((System.currentTimeMillis() - lastReconnectTime) < 1000L)
901 {
902 // If the last reconnect attempt was less than 1 second ago, then abort.
903 throw new LDAPException(ResultCode.SERVER_DOWN,
904 ERR_CONN_MULTIPLE_FAILURES.get());
905 }
906
907 BindRequest bindRequest = null;
908 if (lastBindRequest != null)
909 {
910 bindRequest = lastBindRequest.getRebindRequest(reconnectAddress,
911 reconnectPort);
912 if (bindRequest == null)
913 {
914 throw new LDAPException(ResultCode.SERVER_DOWN,
915 ERR_CONN_CANNOT_REAUTHENTICATE.get(getHostPort()));
916 }
917 }
918
919 final ExtendedRequest startTLSExtendedRequest = startTLSRequest;
920
921 setDisconnectInfo(DisconnectType.RECONNECT, null, null);
922 terminate(null);
923
924 try
925 {
926 Thread.sleep(1000L);
927 } catch (final Exception e) {}
928
929 connect(reconnectAddress, reconnectPort);
930
931 if (startTLSExtendedRequest != null)
932 {
933 try
934 {
935 final ExtendedResult startTLSResult =
936 processExtendedOperation(startTLSExtendedRequest);
937 if (startTLSResult.getResultCode() != ResultCode.SUCCESS)
938 {
939 throw new LDAPException(startTLSResult);
940 }
941 }
942 catch (final LDAPException le)
943 {
944 debugException(le);
945 setDisconnectInfo(DisconnectType.SECURITY_PROBLEM, null, le);
946 terminate(null);
947
948 throw le;
949 }
950 }
951
952 if (bindRequest != null)
953 {
954 try
955 {
956 bind(bindRequest);
957 }
958 catch (final LDAPException le)
959 {
960 debugException(le);
961 setDisconnectInfo(DisconnectType.BIND_FAILED, null, le);
962 terminate(null);
963
964 throw le;
965 }
966 }
967
968 lastReconnectTime = System.currentTimeMillis();
969 }
970
971
972
973 /**
974 * Sets a flag indicating that the connection should be re-established before
975 * sending the next request.
976 */
977 void setNeedsReconnect()
978 {
979 needsReconnect.set(true);
980 }
981
982
983
984 /**
985 * Indicates whether this connection is currently established.
986 *
987 * @return {@code true} if this connection is currently established, or
988 * {@code false} if it is not.
989 */
990 public boolean isConnected()
991 {
992 final LDAPConnectionInternals internals = connectionInternals;
993
994 if (internals == null)
995 {
996 return false;
997 }
998
999 if (! internals.isConnected())
1000 {
1001 setClosed();
1002 return false;
1003 }
1004
1005 return (! needsReconnect.get());
1006 }
1007
1008
1009
1010 /**
1011 * Converts this clear-text connection to one that encrypts all communication
1012 * using Transport Layer Security. This method is intended for use as a
1013 * helper for processing in the course of the StartTLS extended operation and
1014 * should not be used for other purposes.
1015 *
1016 * @param sslSocketFactory The SSL socket factory to use to convert an
1017 * insecure connection into a secure connection. It
1018 * must not be {@code null}.
1019 *
1020 * @throws LDAPException If a problem occurs while converting this
1021 * connection to use TLS.
1022 */
1023 void convertToTLS(final SSLSocketFactory sslSocketFactory)
1024 throws LDAPException
1025 {
1026 final LDAPConnectionInternals internals = connectionInternals;
1027 if (internals == null)
1028 {
1029 throw new LDAPException(ResultCode.SERVER_DOWN,
1030 ERR_CONN_NOT_ESTABLISHED.get());
1031 }
1032 else
1033 {
1034 internals.convertToTLS(sslSocketFactory);
1035 }
1036 }
1037
1038
1039
1040 /**
1041 * Converts this clear-text connection to one that uses SASL integrity and/or
1042 * confidentiality.
1043 *
1044 * @param saslClient The SASL client that will be used to secure the
1045 * communication.
1046 *
1047 * @throws LDAPException If a problem occurs while attempting to convert the
1048 * connection to use SASL QoP.
1049 */
1050 void applySASLQoP(final SaslClient saslClient)
1051 throws LDAPException
1052 {
1053 final LDAPConnectionInternals internals = connectionInternals;
1054 if (internals == null)
1055 {
1056 throw new LDAPException(ResultCode.SERVER_DOWN,
1057 ERR_CONN_NOT_ESTABLISHED.get());
1058 }
1059 else
1060 {
1061 internals.applySASLQoP(saslClient);
1062 }
1063 }
1064
1065
1066
1067 /**
1068 * Retrieves the set of connection options for this connection. Changes to
1069 * the object that is returned will directly impact this connection.
1070 *
1071 * @return The set of connection options for this connection.
1072 */
1073 public LDAPConnectionOptions getConnectionOptions()
1074 {
1075 return connectionOptions;
1076 }
1077
1078
1079
1080 /**
1081 * Specifies the set of connection options for this connection. Some changes
1082 * may not take effect for operations already in progress, and some changes
1083 * may not take effect for a connection that is already established.
1084 *
1085 * @param connectionOptions The set of connection options for this
1086 * connection. It may be {@code null} if a default
1087 * set of options is to be used.
1088 */
1089 public void setConnectionOptions(
1090 final LDAPConnectionOptions connectionOptions)
1091 {
1092 if (connectionOptions == null)
1093 {
1094 this.connectionOptions = new LDAPConnectionOptions();
1095 }
1096 else
1097 {
1098 final LDAPConnectionOptions newOptions = connectionOptions.duplicate();
1099 if (debugEnabled(DebugType.LDAP) && newOptions.useSynchronousMode() &&
1100 (! connectionOptions.useSynchronousMode()) && isConnected())
1101 {
1102 debug(Level.WARNING, DebugType.LDAP,
1103 "A call to LDAPConnection.setConnectionOptions() with " +
1104 "useSynchronousMode=true will have no effect for this " +
1105 "connection because it is already established. The " +
1106 "useSynchronousMode option must be set before the connection " +
1107 "is established to have any effect.");
1108 }
1109
1110 this.connectionOptions = newOptions;
1111 }
1112
1113 final ReferralConnector rc = this.connectionOptions.getReferralConnector();
1114 if (rc == null)
1115 {
1116 referralConnector = this;
1117 }
1118 else
1119 {
1120 referralConnector = rc;
1121 }
1122 }
1123
1124
1125
1126 /**
1127 * Retrieves the socket factory that was used when creating the socket for the
1128 * last connection attempt (whether successful or unsuccessful) for this LDAP
1129 * connection.
1130 *
1131 * @return The socket factory that was used when creating the socket for the
1132 * last connection attempt for this LDAP connection, or {@code null}
1133 * if no attempt has yet been made to establish this connection.
1134 */
1135 public SocketFactory getLastUsedSocketFactory()
1136 {
1137 return lastUsedSocketFactory;
1138 }
1139
1140
1141
1142 /**
1143 * Retrieves the socket factory to use to create the socket for subsequent
1144 * connection attempts. This may or may not be the socket factory that was
1145 * used to create the current established connection.
1146 *
1147 * @return The socket factory to use to create the socket for subsequent
1148 * connection attempts.
1149 */
1150 public SocketFactory getSocketFactory()
1151 {
1152 return socketFactory;
1153 }
1154
1155
1156
1157 /**
1158 * Specifies the socket factory to use to create the socket for subsequent
1159 * connection attempts. This will not impact any established connection.
1160 *
1161 * @param socketFactory The socket factory to use to create the socket for
1162 * subsequent connection attempts.
1163 */
1164 public void setSocketFactory(final SocketFactory socketFactory)
1165 {
1166 if (socketFactory == null)
1167 {
1168 this.socketFactory = DEFAULT_SOCKET_FACTORY;
1169 }
1170 else
1171 {
1172 this.socketFactory = socketFactory;
1173 }
1174 }
1175
1176
1177
1178 /**
1179 * Retrieves the {@code SSLSession} currently being used to secure
1180 * communication on this connection. This may be available for connections
1181 * that were secured at the time they were created (via an
1182 * {@code SSLSocketFactory}), or for connections secured after their creation
1183 * (via the StartTLS extended operation). This will not be available for
1184 * unencrypted connections, or connections secured in other ways (e.g., via
1185 * SASL QoP).
1186 *
1187 * @return The {@code SSLSession} currently being used to secure
1188 * communication on this connection, or {@code null} if no
1189 * {@code SSLSession} is available.
1190 */
1191 public SSLSession getSSLSession()
1192 {
1193 final LDAPConnectionInternals internals = connectionInternals;
1194
1195 if (internals == null)
1196 {
1197 return null;
1198 }
1199
1200 final Socket socket = internals.getSocket();
1201 if ((socket != null) && (socket instanceof SSLSocket))
1202 {
1203 final SSLSocket sslSocket = (SSLSocket) socket;
1204 return sslSocket.getSession();
1205 }
1206 else
1207 {
1208 return null;
1209 }
1210 }
1211
1212
1213
1214 /**
1215 * Retrieves a value that uniquely identifies this connection within the JVM
1216 * Each {@code LDAPConnection} object will be assigned a different connection
1217 * ID, and that connection ID will not change over the life of the object,
1218 * even if the connection is closed and re-established (whether re-established
1219 * to the same server or a different server).
1220 *
1221 * @return A value that uniquely identifies this connection within the JVM.
1222 */
1223 public long getConnectionID()
1224 {
1225 return connectionID;
1226 }
1227
1228
1229
1230 /**
1231 * Retrieves the user-friendly name that has been assigned to this connection.
1232 *
1233 * @return The user-friendly name that has been assigned to this connection,
1234 * or {@code null} if none has been assigned.
1235 */
1236 public String getConnectionName()
1237 {
1238 return connectionName;
1239 }
1240
1241
1242
1243 /**
1244 * Specifies the user-friendly name that should be used for this connection.
1245 * This name may be used in debugging to help identify the purpose of this
1246 * connection. This will have no effect for connections which are part of a
1247 * connection pool.
1248 *
1249 * @param connectionName The user-friendly name that should be used for this
1250 * connection.
1251 */
1252 public void setConnectionName(final String connectionName)
1253 {
1254 if (connectionPool == null)
1255 {
1256 this.connectionName = connectionName;
1257 if (connectionInternals != null)
1258 {
1259 final LDAPConnectionReader reader =
1260 connectionInternals.getConnectionReader();
1261 reader.updateThreadName();
1262 }
1263 }
1264 }
1265
1266
1267
1268 /**
1269 * Retrieves the connection pool with which this connection is associated, if
1270 * any.
1271 *
1272 * @return The connection pool with which this connection is associated, or
1273 * {@code null} if it is not associated with any connection pool.
1274 */
1275 public AbstractConnectionPool getConnectionPool()
1276 {
1277 return connectionPool;
1278 }
1279
1280
1281
1282 /**
1283 * Retrieves the user-friendly name that has been assigned to the connection
1284 * pool with which this connection is associated.
1285 *
1286 * @return The user-friendly name that has been assigned to the connection
1287 * pool with which this connection is associated, or {@code null} if
1288 * none has been assigned or this connection is not associated with a
1289 * connection pool.
1290 */
1291 public String getConnectionPoolName()
1292 {
1293 return connectionPoolName;
1294 }
1295
1296
1297
1298 /**
1299 * Specifies the user-friendly name that should be used for the connection
1300 * pool with which this connection is associated.
1301 *
1302 * @param connectionPoolName The user-friendly name that should be used for
1303 * the connection pool with which this connection
1304 * is associated.
1305 */
1306 void setConnectionPoolName(final String connectionPoolName)
1307 {
1308 this.connectionPoolName = connectionPoolName;
1309 if (connectionInternals != null)
1310 {
1311 final LDAPConnectionReader reader =
1312 connectionInternals.getConnectionReader();
1313 reader.updateThreadName();
1314 }
1315 }
1316
1317
1318
1319 /**
1320 * Retrieves a string representation of the host and port for the server to
1321 * to which the last connection attempt was made. It does not matter whether
1322 * the connection attempt was successful, nor does it matter whether it is
1323 * still established. This is primarily intended for internal use in error
1324 * messages.
1325 *
1326 * @return A string representation of the host and port for the server to
1327 * which the last connection attempt was made, or an empty string if
1328 * no connection attempt has yet been made on this connection.
1329 */
1330 public String getHostPort()
1331 {
1332 if (hostPort == null)
1333 {
1334 return "";
1335 }
1336 else
1337 {
1338 return hostPort;
1339 }
1340 }
1341
1342
1343
1344 /**
1345 * Retrieves the address of the directory server to which this connection is
1346 * currently established.
1347 *
1348 * @return The address of the directory server to which this connection is
1349 * currently established, or {@code null} if the connection is not
1350 * established.
1351 */
1352 public String getConnectedAddress()
1353 {
1354 final LDAPConnectionInternals internals = connectionInternals;
1355 if (internals == null)
1356 {
1357 return null;
1358 }
1359 else
1360 {
1361 return internals.getHost();
1362 }
1363 }
1364
1365
1366
1367 /**
1368 * Retrieves the string representation of the IP address to which this
1369 * connection is currently established.
1370 *
1371 * @return The string representation of the IP address to which this
1372 * connection is currently established, or {@code null} if the
1373 * connection is not established.
1374 */
1375 public String getConnectedIPAddress()
1376 {
1377 final LDAPConnectionInternals internals = connectionInternals;
1378 if (internals == null)
1379 {
1380 return null;
1381 }
1382 else
1383 {
1384 return internals.getInetAddress().getHostAddress();
1385 }
1386 }
1387
1388
1389
1390 /**
1391 * Retrieves an {@code InetAddress} object that represents the address of the
1392 * server to which this connection is currently established.
1393 *
1394 * @return An {@code InetAddress} that represents the address of the server
1395 * to which this connection is currently established, or {@code null}
1396 * if the connection is not established.
1397 */
1398 public InetAddress getConnectedInetAddress()
1399 {
1400 final LDAPConnectionInternals internals = connectionInternals;
1401 if (internals == null)
1402 {
1403 return null;
1404 }
1405 else
1406 {
1407 return internals.getInetAddress();
1408 }
1409 }
1410
1411
1412
1413 /**
1414 * Retrieves the port of the directory server to which this connection is
1415 * currently established.
1416 *
1417 * @return The port of the directory server to which this connection is
1418 * currently established, or -1 if the connection is not established.
1419 */
1420 public int getConnectedPort()
1421 {
1422 final LDAPConnectionInternals internals = connectionInternals;
1423 if (internals == null)
1424 {
1425 return -1;
1426 }
1427 else
1428 {
1429 return internals.getPort();
1430 }
1431 }
1432
1433
1434
1435 /**
1436 * Retrieves a stack trace of the thread that last attempted to establish this
1437 * connection. Note that this will only be available if an attempt has been
1438 * made to establish this connection and the
1439 * {@link LDAPConnectionOptions#captureConnectStackTrace()} method for the
1440 * associated connection options returns {@code true}.
1441 *
1442 * @return A stack trace of the thread that last attempted to establish this
1443 * connection, or {@code null} connect stack traces are not enabled,
1444 * or if no attempt has been made to establish this connection.
1445 */
1446 public StackTraceElement[] getConnectStackTrace()
1447 {
1448 return connectStackTrace;
1449 }
1450
1451
1452
1453 /**
1454 * Provides a stack trace for the thread that last attempted to establish this
1455 * connection.
1456 *
1457 * @param connectStackTrace A stack trace for the thread that last attempted
1458 * to establish this connection.
1459 */
1460 void setConnectStackTrace(final StackTraceElement[] connectStackTrace)
1461 {
1462 this.connectStackTrace = connectStackTrace;
1463 }
1464
1465
1466
1467 /**
1468 * Unbinds from the server and closes the connection.
1469 * <BR><BR>
1470 * If this method is invoked while any operations are in progress on this
1471 * connection, then the directory server may or may not abort processing for
1472 * those operations, depending on the type of operation and how far along the
1473 * server has already gotten while processing that operation. It is
1474 * recommended that all active operations be abandoned, canceled, or allowed
1475 * to complete before attempting to close an active connection.
1476 */
1477 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
1478 public void close()
1479 {
1480 close(NO_CONTROLS);
1481 }
1482
1483
1484
1485 /**
1486 * Unbinds from the server and closes the connection, optionally including
1487 * the provided set of controls in the unbind request.
1488 * <BR><BR>
1489 * If this method is invoked while any operations are in progress on this
1490 * connection, then the directory server may or may not abort processing for
1491 * those operations, depending on the type of operation and how far along the
1492 * server has already gotten while processing that operation. It is
1493 * recommended that all active operations be abandoned, canceled, or allowed
1494 * to complete before attempting to close an active connection.
1495 *
1496 * @param controls The set of controls to include in the unbind request. It
1497 * may be {@code null} if there are not to be any controls
1498 * sent in the unbind request.
1499 */
1500 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
1501 public void close(final Control[] controls)
1502 {
1503 closeRequested = true;
1504 setDisconnectInfo(DisconnectType.UNBIND, null, null);
1505
1506 if (connectionPool == null)
1507 {
1508 terminate(controls);
1509 }
1510 else
1511 {
1512 connectionPool.releaseDefunctConnection(this);
1513 }
1514 }
1515
1516
1517
1518 /**
1519 * Unbinds from the server and closes the connection, optionally including the
1520 * provided set of controls in the unbind request. This method is only
1521 * intended for internal use, since it does not make any attempt to release
1522 * the connection back to its associated connection pool, if there is one.
1523 *
1524 * @param controls The set of controls to include in the unbind request. It
1525 * may be {@code null} if there are not to be any controls
1526 * sent in the unbind request.
1527 */
1528 void terminate(final Control[] controls)
1529 {
1530 if (isConnected() && (! unbindRequestSent))
1531 {
1532 try
1533 {
1534 unbindRequestSent = true;
1535 setDisconnectInfo(DisconnectType.UNBIND, null, null);
1536 if (debugEnabled(DebugType.LDAP))
1537 {
1538 debug(Level.INFO, DebugType.LDAP, "Sending LDAP unbind request.");
1539 }
1540
1541 connectionStatistics.incrementNumUnbindRequests();
1542 sendMessage(new LDAPMessage(nextMessageID(),
1543 new UnbindRequestProtocolOp(), controls));
1544 }
1545 catch (Exception e)
1546 {
1547 debugException(e);
1548 }
1549 }
1550
1551 setClosed();
1552 }
1553
1554
1555
1556 /**
1557 * Indicates whether a request has been made to close this connection.
1558 *
1559 * @return {@code true} if a request has been made to close this connection,
1560 * or {@code false} if not.
1561 */
1562 boolean closeRequested()
1563 {
1564 return closeRequested;
1565 }
1566
1567
1568
1569 /**
1570 * Indicates whether an unbind request has been sent over this connection.
1571 *
1572 * @return {@code true} if an unbind request has been sent over this
1573 * connection, or {@code false} if not.
1574 */
1575 boolean unbindRequestSent()
1576 {
1577 return unbindRequestSent;
1578 }
1579
1580
1581
1582 /**
1583 * Indicates that this LDAP connection is part of the specified
1584 * connection pool.
1585 *
1586 * @param connectionPool The connection pool with which this LDAP connection
1587 * is associated.
1588 */
1589 void setConnectionPool(final AbstractConnectionPool connectionPool)
1590 {
1591 this.connectionPool = connectionPool;
1592 }
1593
1594
1595
1596 /**
1597 * Retrieves the directory server root DSE, which provides information about
1598 * the directory server, including the capabilities that it provides and the
1599 * type of data that it is configured to handle.
1600 *
1601 * @return The directory server root DSE, or {@code null} if it is not
1602 * available.
1603 *
1604 * @throws LDAPException If a problem occurs while attempting to retrieve
1605 * the server root DSE.
1606 */
1607 public RootDSE getRootDSE()
1608 throws LDAPException
1609 {
1610 return RootDSE.getRootDSE(this);
1611 }
1612
1613
1614
1615 /**
1616 * Retrieves the directory server schema definitions, using the subschema
1617 * subentry DN contained in the server's root DSE. For directory servers
1618 * containing a single schema, this should be sufficient for all purposes.
1619 * For servers with multiple schemas, it may be necessary to specify the DN
1620 * of the target entry for which to obtain the associated schema.
1621 *
1622 * @return The directory server schema definitions, or {@code null} if the
1623 * schema information could not be retrieved (e.g, the client does
1624 * not have permission to read the server schema).
1625 *
1626 * @throws LDAPException If a problem occurs while attempting to retrieve
1627 * the server schema.
1628 */
1629 public Schema getSchema()
1630 throws LDAPException
1631 {
1632 return Schema.getSchema(this, "");
1633 }
1634
1635
1636
1637 /**
1638 * Retrieves the directory server schema definitions that govern the specified
1639 * entry. The subschemaSubentry attribute will be retrieved from the target
1640 * entry, and then the appropriate schema definitions will be loaded from the
1641 * entry referenced by that attribute. This may be necessary to ensure
1642 * correct behavior in servers that support multiple schemas.
1643 *
1644 * @param entryDN The DN of the entry for which to retrieve the associated
1645 * schema definitions. It may be {@code null} or an empty
1646 * string if the subschemaSubentry attribute should be
1647 * retrieved from the server's root DSE.
1648 *
1649 * @return The directory server schema definitions, or {@code null} if the
1650 * schema information could not be retrieved (e.g, the client does
1651 * not have permission to read the server schema).
1652 *
1653 * @throws LDAPException If a problem occurs while attempting to retrieve
1654 * the server schema.
1655 */
1656 public Schema getSchema(final String entryDN)
1657 throws LDAPException
1658 {
1659 return Schema.getSchema(this, entryDN);
1660 }
1661
1662
1663
1664 /**
1665 * Retrieves the entry with the specified DN. All user attributes will be
1666 * requested in the entry to return.
1667 *
1668 * @param dn The DN of the entry to retrieve. It must not be {@code null}.
1669 *
1670 * @return The requested entry, or {@code null} if the target entry does not
1671 * exist or no entry was returned (e.g., if the authenticated user
1672 * does not have permission to read the target entry).
1673 *
1674 * @throws LDAPException If a problem occurs while sending the request or
1675 * reading the response.
1676 */
1677 public SearchResultEntry getEntry(final String dn)
1678 throws LDAPException
1679 {
1680 return getEntry(dn, (String[]) null);
1681 }
1682
1683
1684
1685 /**
1686 * Retrieves the entry with the specified DN.
1687 *
1688 * @param dn The DN of the entry to retrieve. It must not be
1689 * {@code null}.
1690 * @param attributes The set of attributes to request for the target entry.
1691 * If it is {@code null}, then all user attributes will be
1692 * requested.
1693 *
1694 * @return The requested entry, or {@code null} if the target entry does not
1695 * exist or no entry was returned (e.g., if the authenticated user
1696 * does not have permission to read the target entry).
1697 *
1698 * @throws LDAPException If a problem occurs while sending the request or
1699 * reading the response.
1700 */
1701 public SearchResultEntry getEntry(final String dn, final String... attributes)
1702 throws LDAPException
1703 {
1704 final Filter filter = Filter.createPresenceFilter("objectClass");
1705
1706 final SearchResult result;
1707 try
1708 {
1709 final SearchRequest searchRequest =
1710 new SearchRequest(dn, SearchScope.BASE, DereferencePolicy.NEVER, 1,
1711 0, false, filter, attributes);
1712 result = search(searchRequest);
1713 }
1714 catch (LDAPException le)
1715 {
1716 if (le.getResultCode().equals(ResultCode.NO_SUCH_OBJECT))
1717 {
1718 return null;
1719 }
1720 else
1721 {
1722 throw le;
1723 }
1724 }
1725
1726 if (! result.getResultCode().equals(ResultCode.SUCCESS))
1727 {
1728 throw new LDAPException(result);
1729 }
1730
1731 final List<SearchResultEntry> entryList = result.getSearchEntries();
1732 if (entryList.isEmpty())
1733 {
1734 return null;
1735 }
1736 else
1737 {
1738 return entryList.get(0);
1739 }
1740 }
1741
1742
1743
1744 /**
1745 * Processes an abandon request with the provided information.
1746 *
1747 * @param requestID The async request ID for the request to abandon.
1748 *
1749 * @throws LDAPException If a problem occurs while sending the request to
1750 * the server.
1751 */
1752 public void abandon(final AsyncRequestID requestID)
1753 throws LDAPException
1754 {
1755 abandon(requestID, null);
1756 }
1757
1758
1759
1760 /**
1761 * Processes an abandon request with the provided information.
1762 *
1763 * @param requestID The async request ID for the request to abandon.
1764 * @param controls The set of controls to include in the abandon request.
1765 * It may be {@code null} or empty if there are no
1766 * controls.
1767 *
1768 * @throws LDAPException If a problem occurs while sending the request to
1769 * the server.
1770 */
1771 public void abandon(final AsyncRequestID requestID, final Control[] controls)
1772 throws LDAPException
1773 {
1774 if (debugEnabled(DebugType.LDAP))
1775 {
1776 debug(Level.INFO, DebugType.LDAP,
1777 "Sending LDAP abandon request for message ID " + requestID);
1778 }
1779
1780 if (synchronousMode())
1781 {
1782 throw new LDAPException(ResultCode.NOT_SUPPORTED,
1783 ERR_ABANDON_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
1784 }
1785
1786 final int messageID = requestID.getMessageID();
1787 try
1788 {
1789 connectionInternals.getConnectionReader().deregisterResponseAcceptor(
1790 messageID);
1791 }
1792 catch (final Exception e)
1793 {
1794 debugException(e);
1795 }
1796
1797 connectionStatistics.incrementNumAbandonRequests();
1798 sendMessage(new LDAPMessage(nextMessageID(),
1799 new AbandonRequestProtocolOp(messageID), controls));
1800 }
1801
1802
1803
1804 /**
1805 * Sends an abandon request with the provided information.
1806 *
1807 * @param messageID The message ID for the request to abandon.
1808 * @param controls The set of controls to include in the abandon request.
1809 * It may be {@code null} or empty if there are no
1810 * controls.
1811 *
1812 * @throws LDAPException If a problem occurs while sending the request to
1813 * the server.
1814 */
1815 void abandon(final int messageID, final Control... controls)
1816 throws LDAPException
1817 {
1818 if (debugEnabled(DebugType.LDAP))
1819 {
1820 debug(Level.INFO, DebugType.LDAP,
1821 "Sending LDAP abandon request for message ID " + messageID);
1822 }
1823
1824 try
1825 {
1826 connectionInternals.getConnectionReader().deregisterResponseAcceptor(
1827 messageID);
1828 }
1829 catch (final Exception e)
1830 {
1831 debugException(e);
1832 }
1833
1834 connectionStatistics.incrementNumAbandonRequests();
1835 sendMessage(new LDAPMessage(nextMessageID(),
1836 new AbandonRequestProtocolOp(messageID), controls));
1837 }
1838
1839
1840
1841 /**
1842 * Processes an add operation with the provided information.
1843 *
1844 * @param dn The DN of the entry to add. It must not be
1845 * {@code null}.
1846 * @param attributes The set of attributes to include in the entry to add.
1847 * It must not be {@code null}.
1848 *
1849 * @return The result of processing the add operation.
1850 *
1851 * @throws LDAPException If the server rejects the add request, or if a
1852 * problem is encountered while sending the request or
1853 * reading the response.
1854 */
1855 public LDAPResult add(final String dn, final Attribute... attributes)
1856 throws LDAPException
1857 {
1858 ensureNotNull(dn, attributes);
1859
1860 return add(new AddRequest(dn, attributes));
1861 }
1862
1863
1864
1865 /**
1866 * Processes an add operation with the provided information.
1867 *
1868 * @param dn The DN of the entry to add. It must not be
1869 * {@code null}.
1870 * @param attributes The set of attributes to include in the entry to add.
1871 * It must not be {@code null}.
1872 *
1873 * @return The result of processing the add operation.
1874 *
1875 * @throws LDAPException If the server rejects the add request, or if a
1876 * problem is encountered while sending the request or
1877 * reading the response.
1878 */
1879 public LDAPResult add(final String dn, final Collection<Attribute> attributes)
1880 throws LDAPException
1881 {
1882 ensureNotNull(dn, attributes);
1883
1884 return add(new AddRequest(dn, attributes));
1885 }
1886
1887
1888
1889 /**
1890 * Processes an add operation with the provided information.
1891 *
1892 * @param entry The entry to add. It must not be {@code null}.
1893 *
1894 * @return The result of processing the add operation.
1895 *
1896 * @throws LDAPException If the server rejects the add request, or if a
1897 * problem is encountered while sending the request or
1898 * reading the response.
1899 */
1900 public LDAPResult add(final Entry entry)
1901 throws LDAPException
1902 {
1903 ensureNotNull(entry);
1904
1905 return add(new AddRequest(entry));
1906 }
1907
1908
1909
1910 /**
1911 * Processes an add operation with the provided information.
1912 *
1913 * @param ldifLines The lines that comprise an LDIF representation of the
1914 * entry to add. It must not be empty or {@code null}.
1915 *
1916 * @return The result of processing the add operation.
1917 *
1918 * @throws LDIFException If the provided entry lines cannot be decoded as an
1919 * entry in LDIF form.
1920 *
1921 * @throws LDAPException If the server rejects the add request, or if a
1922 * problem is encountered while sending the request or
1923 * reading the response.
1924 */
1925 public LDAPResult add(final String... ldifLines)
1926 throws LDIFException, LDAPException
1927 {
1928 return add(new AddRequest(ldifLines));
1929 }
1930
1931
1932
1933 /**
1934 * Processes the provided add request.
1935 *
1936 * @param addRequest The add request to be processed. It must not be
1937 * {@code null}.
1938 *
1939 * @return The result of processing the add operation.
1940 *
1941 * @throws LDAPException If the server rejects the add request, or if a
1942 * problem is encountered while sending the request or
1943 * reading the response.
1944 */
1945 public LDAPResult add(final AddRequest addRequest)
1946 throws LDAPException
1947 {
1948 ensureNotNull(addRequest);
1949
1950 final LDAPResult ldapResult = addRequest.process(this, 1);
1951
1952 switch (ldapResult.getResultCode().intValue())
1953 {
1954 case ResultCode.SUCCESS_INT_VALUE:
1955 case ResultCode.NO_OPERATION_INT_VALUE:
1956 return ldapResult;
1957
1958 default:
1959 throw new LDAPException(ldapResult);
1960 }
1961 }
1962
1963
1964
1965 /**
1966 * Processes the provided add request.
1967 *
1968 * @param addRequest The add request to be processed. It must not be
1969 * {@code null}.
1970 *
1971 * @return The result of processing the add operation.
1972 *
1973 * @throws LDAPException If the server rejects the add request, or if a
1974 * problem is encountered while sending the request or
1975 * reading the response.
1976 */
1977 public LDAPResult add(final ReadOnlyAddRequest addRequest)
1978 throws LDAPException
1979 {
1980 return add((AddRequest) addRequest);
1981 }
1982
1983
1984
1985 /**
1986 * Processes the provided add request as an asynchronous operation.
1987 *
1988 * @param addRequest The add request to be processed. It must not be
1989 * {@code null}.
1990 * @param resultListener The async result listener to use to handle the
1991 * response for the add operation. It may be
1992 * {@code null} if the result is going to be obtained
1993 * from the returned {@code AsyncRequestID} object via
1994 * the {@code Future} API.
1995 *
1996 * @return An async request ID that may be used to reference the operation.
1997 *
1998 * @throws LDAPException If a problem occurs while sending the request.
1999 */
2000 public AsyncRequestID asyncAdd(final AddRequest addRequest,
2001 final AsyncResultListener resultListener)
2002 throws LDAPException
2003 {
2004 ensureNotNull(addRequest);
2005
2006 if (synchronousMode())
2007 {
2008 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2009 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2010 }
2011
2012 final AsyncResultListener listener;
2013 if (resultListener == null)
2014 {
2015 listener = DiscardAsyncListener.getInstance();
2016 }
2017 else
2018 {
2019 listener = resultListener;
2020 }
2021
2022 return addRequest.processAsync(this, listener);
2023 }
2024
2025
2026
2027 /**
2028 * Processes the provided add request as an asynchronous operation.
2029 *
2030 * @param addRequest The add request to be processed. It must not be
2031 * {@code null}.
2032 * @param resultListener The async result listener to use to handle the
2033 * response for the add operation. It may be
2034 * {@code null} if the result is going to be obtained
2035 * from the returned {@code AsyncRequestID} object via
2036 * the {@code Future} API.
2037 *
2038 * @return An async request ID that may be used to reference the operation.
2039 *
2040 * @throws LDAPException If a problem occurs while sending the request.
2041 */
2042 public AsyncRequestID asyncAdd(final ReadOnlyAddRequest addRequest,
2043 final AsyncResultListener resultListener)
2044 throws LDAPException
2045 {
2046 if (synchronousMode())
2047 {
2048 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2049 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2050 }
2051
2052 return asyncAdd((AddRequest) addRequest, resultListener);
2053 }
2054
2055
2056
2057 /**
2058 * Processes a simple bind request with the provided DN and password.
2059 * <BR><BR>
2060 * The LDAP protocol specification forbids clients from attempting to perform
2061 * a bind on a connection in which one or more other operations are already in
2062 * progress. If a bind is attempted while any operations are in progress,
2063 * then the directory server may or may not abort processing for those
2064 * operations, depending on the type of operation and how far along the
2065 * server has already gotten while processing that operation (unless the bind
2066 * request is one that will not cause the server to attempt to change the
2067 * identity of this connection, for example by including the retain identity
2068 * request control in the bind request if using the Commercial Edition of the
2069 * LDAP SDK in conjunction with a Ping Identity, UnboundID, or Alcatel-Lucent
2070 * 8661 Directory Server). It is recommended that all active operations be
2071 * abandoned, canceled, or allowed to complete before attempting to perform a
2072 * bind on an active connection.
2073 *
2074 * @param bindDN The bind DN for the bind operation.
2075 * @param password The password for the simple bind operation.
2076 *
2077 * @return The result of processing the bind operation.
2078 *
2079 * @throws LDAPException If the server rejects the bind request, or if a
2080 * problem occurs while sending the request or reading
2081 * the response.
2082 */
2083 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
2084 public BindResult bind(final String bindDN, final String password)
2085 throws LDAPException
2086 {
2087 return bind(new SimpleBindRequest(bindDN, password));
2088 }
2089
2090
2091
2092 /**
2093 * Processes the provided bind request.
2094 * <BR><BR>
2095 * The LDAP protocol specification forbids clients from attempting to perform
2096 * a bind on a connection in which one or more other operations are already in
2097 * progress. If a bind is attempted while any operations are in progress,
2098 * then the directory server may or may not abort processing for those
2099 * operations, depending on the type of operation and how far along the
2100 * server has already gotten while processing that operation (unless the bind
2101 * request is one that will not cause the server to attempt to change the
2102 * identity of this connection, for example by including the retain identity
2103 * request control in the bind request if using the Commercial Edition of the
2104 * LDAP SDK in conjunction with a Ping Identity, UnboundID, or Alcatel-Lucent
2105 * 8661 Directory Server). It is recommended that all active operations be
2106 * abandoned, canceled, or allowed to complete before attempting to perform a
2107 * bind on an active connection.
2108 *
2109 * @param bindRequest The bind request to be processed. It must not be
2110 * {@code null}.
2111 *
2112 * @return The result of processing the bind operation.
2113 *
2114 * @throws LDAPException If the server rejects the bind request, or if a
2115 * problem occurs while sending the request or reading
2116 * the response.
2117 */
2118 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
2119 public BindResult bind(final BindRequest bindRequest)
2120 throws LDAPException
2121 {
2122 ensureNotNull(bindRequest);
2123
2124 // We don't want to update the last bind request or update the cached
2125 // schema for this connection if it included the retain identity control.
2126 // However, that's only available in the Commercial Edition, so just
2127 // reference it by OID here.
2128 boolean hasRetainIdentityControl = false;
2129 for (final Control c : bindRequest.getControls())
2130 {
2131 if (c.getOID().equals("1.3.6.1.4.1.30221.2.5.3"))
2132 {
2133 hasRetainIdentityControl = true;
2134 break;
2135 }
2136 }
2137
2138 if (! hasRetainIdentityControl)
2139 {
2140 lastBindRequest = null;
2141 }
2142
2143 final BindResult bindResult = bindRequest.process(this, 1);
2144 if (bindResult.getResultCode().equals(ResultCode.SUCCESS))
2145 {
2146 if (! hasRetainIdentityControl)
2147 {
2148 lastBindRequest = bindRequest;
2149 if (connectionOptions.useSchema())
2150 {
2151 try
2152 {
2153 cachedSchema = getCachedSchema(this);
2154 }
2155 catch (Exception e)
2156 {
2157 debugException(e);
2158 }
2159 }
2160 }
2161
2162 return bindResult;
2163 }
2164
2165 if (bindResult.getResultCode().equals(ResultCode.SASL_BIND_IN_PROGRESS))
2166 {
2167 throw new SASLBindInProgressException(bindResult);
2168 }
2169 else
2170 {
2171 throw new LDAPBindException(bindResult);
2172 }
2173 }
2174
2175
2176
2177 /**
2178 * Processes a compare operation with the provided information.
2179 *
2180 * @param dn The DN of the entry in which to make the
2181 * comparison. It must not be {@code null}.
2182 * @param attributeName The attribute name for which to make the
2183 * comparison. It must not be {@code null}.
2184 * @param assertionValue The assertion value to verify in the target entry.
2185 * It must not be {@code null}.
2186 *
2187 * @return The result of processing the compare operation.
2188 *
2189 * @throws LDAPException If the server rejects the compare request, or if a
2190 * problem is encountered while sending the request or
2191 * reading the response.
2192 */
2193 public CompareResult compare(final String dn, final String attributeName,
2194 final String assertionValue)
2195 throws LDAPException
2196 {
2197 ensureNotNull(dn, attributeName, assertionValue);
2198
2199 return compare(new CompareRequest(dn, attributeName, assertionValue));
2200 }
2201
2202
2203
2204 /**
2205 * Processes the provided compare request.
2206 *
2207 * @param compareRequest The compare request to be processed. It must not
2208 * be {@code null}.
2209 *
2210 * @return The result of processing the compare operation.
2211 *
2212 * @throws LDAPException If the server rejects the compare request, or if a
2213 * problem is encountered while sending the request or
2214 * reading the response.
2215 */
2216 public CompareResult compare(final CompareRequest compareRequest)
2217 throws LDAPException
2218 {
2219 ensureNotNull(compareRequest);
2220
2221 final LDAPResult result = compareRequest.process(this, 1);
2222 switch (result.getResultCode().intValue())
2223 {
2224 case ResultCode.COMPARE_FALSE_INT_VALUE:
2225 case ResultCode.COMPARE_TRUE_INT_VALUE:
2226 return new CompareResult(result);
2227
2228 default:
2229 throw new LDAPException(result);
2230 }
2231 }
2232
2233
2234
2235 /**
2236 * Processes the provided compare request.
2237 *
2238 * @param compareRequest The compare request to be processed. It must not
2239 * be {@code null}.
2240 *
2241 * @return The result of processing the compare operation.
2242 *
2243 * @throws LDAPException If the server rejects the compare request, or if a
2244 * problem is encountered while sending the request or
2245 * reading the response.
2246 */
2247 public CompareResult compare(final ReadOnlyCompareRequest compareRequest)
2248 throws LDAPException
2249 {
2250 return compare((CompareRequest) compareRequest);
2251 }
2252
2253
2254
2255 /**
2256 * Processes the provided compare request as an asynchronous operation.
2257 *
2258 * @param compareRequest The compare request to be processed. It must not
2259 * be {@code null}.
2260 * @param resultListener The async result listener to use to handle the
2261 * response for the compare operation. It may be
2262 * {@code null} if the result is going to be obtained
2263 * from the returned {@code AsyncRequestID} object via
2264 * the {@code Future} API.
2265 *
2266 * @return An async request ID that may be used to reference the operation.
2267 *
2268 * @throws LDAPException If a problem occurs while sending the request.
2269 */
2270 public AsyncRequestID asyncCompare(final CompareRequest compareRequest,
2271 final AsyncCompareResultListener resultListener)
2272 throws LDAPException
2273 {
2274 ensureNotNull(compareRequest);
2275
2276 if (synchronousMode())
2277 {
2278 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2279 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2280 }
2281
2282 final AsyncCompareResultListener listener;
2283 if (resultListener == null)
2284 {
2285 listener = DiscardAsyncListener.getInstance();
2286 }
2287 else
2288 {
2289 listener = resultListener;
2290 }
2291
2292 return compareRequest.processAsync(this, listener);
2293 }
2294
2295
2296
2297 /**
2298 * Processes the provided compare request as an asynchronous operation.
2299 *
2300 * @param compareRequest The compare request to be processed. It must not
2301 * be {@code null}.
2302 * @param resultListener The async result listener to use to handle the
2303 * response for the compare operation. It may be
2304 * {@code null} if the result is going to be obtained
2305 * from the returned {@code AsyncRequestID} object via
2306 * the {@code Future} API.
2307 *
2308 * @return An async request ID that may be used to reference the operation.
2309 *
2310 * @throws LDAPException If a problem occurs while sending the request.
2311 */
2312 public AsyncRequestID asyncCompare(
2313 final ReadOnlyCompareRequest compareRequest,
2314 final AsyncCompareResultListener resultListener)
2315 throws LDAPException
2316 {
2317 if (synchronousMode())
2318 {
2319 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2320 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2321 }
2322
2323 return asyncCompare((CompareRequest) compareRequest, resultListener);
2324 }
2325
2326
2327
2328 /**
2329 * Deletes the entry with the specified DN.
2330 *
2331 * @param dn The DN of the entry to delete. It must not be {@code null}.
2332 *
2333 * @return The result of processing the delete operation.
2334 *
2335 * @throws LDAPException If the server rejects the delete request, or if a
2336 * problem is encountered while sending the request or
2337 * reading the response.
2338 */
2339 public LDAPResult delete(final String dn)
2340 throws LDAPException
2341 {
2342 return delete(new DeleteRequest(dn));
2343 }
2344
2345
2346
2347 /**
2348 * Processes the provided delete request.
2349 *
2350 * @param deleteRequest The delete request to be processed. It must not be
2351 * {@code null}.
2352 *
2353 * @return The result of processing the delete operation.
2354 *
2355 * @throws LDAPException If the server rejects the delete request, or if a
2356 * problem is encountered while sending the request or
2357 * reading the response.
2358 */
2359 public LDAPResult delete(final DeleteRequest deleteRequest)
2360 throws LDAPException
2361 {
2362 ensureNotNull(deleteRequest);
2363
2364 final LDAPResult ldapResult = deleteRequest.process(this, 1);
2365
2366 switch (ldapResult.getResultCode().intValue())
2367 {
2368 case ResultCode.SUCCESS_INT_VALUE:
2369 case ResultCode.NO_OPERATION_INT_VALUE:
2370 return ldapResult;
2371
2372 default:
2373 throw new LDAPException(ldapResult);
2374 }
2375 }
2376
2377
2378
2379 /**
2380 * Processes the provided delete request.
2381 *
2382 * @param deleteRequest The delete request to be processed. It must not be
2383 * {@code null}.
2384 *
2385 * @return The result of processing the delete operation.
2386 *
2387 * @throws LDAPException If the server rejects the delete request, or if a
2388 * problem is encountered while sending the request or
2389 * reading the response.
2390 */
2391 public LDAPResult delete(final ReadOnlyDeleteRequest deleteRequest)
2392 throws LDAPException
2393 {
2394 return delete((DeleteRequest) deleteRequest);
2395 }
2396
2397
2398
2399 /**
2400 * Processes the provided delete request as an asynchronous operation.
2401 *
2402 * @param deleteRequest The delete request to be processed. It must not be
2403 * {@code null}.
2404 * @param resultListener The async result listener to use to handle the
2405 * response for the delete operation. It may be
2406 * {@code null} if the result is going to be obtained
2407 * from the returned {@code AsyncRequestID} object via
2408 * the {@code Future} API.
2409 *
2410 * @return An async request ID that may be used to reference the operation.
2411 *
2412 * @throws LDAPException If a problem occurs while sending the request.
2413 */
2414 public AsyncRequestID asyncDelete(final DeleteRequest deleteRequest,
2415 final AsyncResultListener resultListener)
2416 throws LDAPException
2417 {
2418 ensureNotNull(deleteRequest);
2419
2420 if (synchronousMode())
2421 {
2422 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2423 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2424 }
2425
2426 final AsyncResultListener listener;
2427 if (resultListener == null)
2428 {
2429 listener = DiscardAsyncListener.getInstance();
2430 }
2431 else
2432 {
2433 listener = resultListener;
2434 }
2435
2436 return deleteRequest.processAsync(this, listener);
2437 }
2438
2439
2440
2441 /**
2442 * Processes the provided delete request as an asynchronous operation.
2443 *
2444 * @param deleteRequest The delete request to be processed. It must not be
2445 * {@code null}.
2446 * @param resultListener The async result listener to use to handle the
2447 * response for the delete operation. It may be
2448 * {@code null} if the result is going to be obtained
2449 * from the returned {@code AsyncRequestID} object via
2450 * the {@code Future} API.
2451 *
2452 * @return An async request ID that may be used to reference the operation.
2453 *
2454 * @throws LDAPException If a problem occurs while sending the request.
2455 */
2456 public AsyncRequestID asyncDelete(final ReadOnlyDeleteRequest deleteRequest,
2457 final AsyncResultListener resultListener)
2458 throws LDAPException
2459 {
2460 if (synchronousMode())
2461 {
2462 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2463 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2464 }
2465
2466 return asyncDelete((DeleteRequest) deleteRequest, resultListener);
2467 }
2468
2469
2470
2471 /**
2472 * Processes an extended request with the provided request OID. Note that
2473 * because some types of extended operations return unusual result codes under
2474 * "normal" conditions, the server may not always throw an exception for a
2475 * failed extended operation like it does for other types of operations. It
2476 * will throw an exception under conditions where there appears to be a
2477 * problem with the connection or the server to which the connection is
2478 * established, but there may be many circumstances in which an extended
2479 * operation is not processed correctly but this method does not throw an
2480 * exception. In the event that no exception is thrown, it is the
2481 * responsibility of the caller to interpret the result to determine whether
2482 * the operation was processed as expected.
2483 * <BR><BR>
2484 * Note that extended operations which may change the state of this connection
2485 * (e.g., the StartTLS extended operation, which will add encryption to a
2486 * previously-unencrypted connection) should not be invoked while any other
2487 * operations are active on the connection. It is recommended that all active
2488 * operations be abandoned, canceled, or allowed to complete before attempting
2489 * to process an extended operation that may change the state of this
2490 * connection.
2491 *
2492 * @param requestOID The OID for the extended request to process. It must
2493 * not be {@code null}.
2494 *
2495 * @return The extended result object that provides information about the
2496 * result of the request processing. It may or may not indicate that
2497 * the operation was successful.
2498 *
2499 * @throws LDAPException If a problem occurs while sending the request or
2500 * reading the response.
2501 */
2502 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
2503 public ExtendedResult processExtendedOperation(final String requestOID)
2504 throws LDAPException
2505 {
2506 ensureNotNull(requestOID);
2507
2508 return processExtendedOperation(new ExtendedRequest(requestOID));
2509 }
2510
2511
2512
2513 /**
2514 * Processes an extended request with the provided request OID and value.
2515 * Note that because some types of extended operations return unusual result
2516 * codes under "normal" conditions, the server may not always throw an
2517 * exception for a failed extended operation like it does for other types of
2518 * operations. It will throw an exception under conditions where there
2519 * appears to be a problem with the connection or the server to which the
2520 * connection is established, but there may be many circumstances in which an
2521 * extended operation is not processed correctly but this method does not
2522 * throw an exception. In the event that no exception is thrown, it is the
2523 * responsibility of the caller to interpret the result to determine whether
2524 * the operation was processed as expected.
2525 * <BR><BR>
2526 * Note that extended operations which may change the state of this connection
2527 * (e.g., the StartTLS extended operation, which will add encryption to a
2528 * previously-unencrypted connection) should not be invoked while any other
2529 * operations are active on the connection. It is recommended that all active
2530 * operations be abandoned, canceled, or allowed to complete before attempting
2531 * to process an extended operation that may change the state of this
2532 * connection.
2533 *
2534 * @param requestOID The OID for the extended request to process. It must
2535 * not be {@code null}.
2536 * @param requestValue The encoded value for the extended request to
2537 * process. It may be {@code null} if there does not
2538 * need to be a value for the requested operation.
2539 *
2540 * @return The extended result object that provides information about the
2541 * result of the request processing. It may or may not indicate that
2542 * the operation was successful.
2543 *
2544 * @throws LDAPException If a problem occurs while sending the request or
2545 * reading the response.
2546 */
2547 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
2548 public ExtendedResult processExtendedOperation(final String requestOID,
2549 final ASN1OctetString requestValue)
2550 throws LDAPException
2551 {
2552 ensureNotNull(requestOID);
2553
2554 return processExtendedOperation(new ExtendedRequest(requestOID,
2555 requestValue));
2556 }
2557
2558
2559
2560 /**
2561 * Processes the provided extended request. Note that because some types of
2562 * extended operations return unusual result codes under "normal" conditions,
2563 * the server may not always throw an exception for a failed extended
2564 * operation like it does for other types of operations. It will throw an
2565 * exception under conditions where there appears to be a problem with the
2566 * connection or the server to which the connection is established, but there
2567 * may be many circumstances in which an extended operation is not processed
2568 * correctly but this method does not throw an exception. In the event that
2569 * no exception is thrown, it is the responsibility of the caller to interpret
2570 * the result to determine whether the operation was processed as expected.
2571 * <BR><BR>
2572 * Note that extended operations which may change the state of this connection
2573 * (e.g., the StartTLS extended operation, which will add encryption to a
2574 * previously-unencrypted connection) should not be invoked while any other
2575 * operations are active on the connection. It is recommended that all active
2576 * operations be abandoned, canceled, or allowed to complete before attempting
2577 * to process an extended operation that may change the state of this
2578 * connection.
2579 *
2580 * @param extendedRequest The extended request to be processed. It must not
2581 * be {@code null}.
2582 *
2583 * @return The extended result object that provides information about the
2584 * result of the request processing. It may or may not indicate that
2585 * the operation was successful.
2586 *
2587 * @throws LDAPException If a problem occurs while sending the request or
2588 * reading the response.
2589 */
2590 @ThreadSafety(level=ThreadSafetyLevel.METHOD_NOT_THREADSAFE)
2591 public ExtendedResult processExtendedOperation(
2592 final ExtendedRequest extendedRequest)
2593 throws LDAPException
2594 {
2595 ensureNotNull(extendedRequest);
2596
2597 final ExtendedResult extendedResult = extendedRequest.process(this, 1);
2598
2599 if ((extendedResult.getOID() == null) &&
2600 (extendedResult.getValue() == null))
2601 {
2602 switch (extendedResult.getResultCode().intValue())
2603 {
2604 case ResultCode.OPERATIONS_ERROR_INT_VALUE:
2605 case ResultCode.PROTOCOL_ERROR_INT_VALUE:
2606 case ResultCode.BUSY_INT_VALUE:
2607 case ResultCode.UNAVAILABLE_INT_VALUE:
2608 case ResultCode.OTHER_INT_VALUE:
2609 case ResultCode.SERVER_DOWN_INT_VALUE:
2610 case ResultCode.LOCAL_ERROR_INT_VALUE:
2611 case ResultCode.ENCODING_ERROR_INT_VALUE:
2612 case ResultCode.DECODING_ERROR_INT_VALUE:
2613 case ResultCode.TIMEOUT_INT_VALUE:
2614 case ResultCode.NO_MEMORY_INT_VALUE:
2615 case ResultCode.CONNECT_ERROR_INT_VALUE:
2616 throw new LDAPException(extendedResult);
2617 }
2618 }
2619
2620 if ((extendedResult.getResultCode() == ResultCode.SUCCESS) &&
2621 extendedRequest.getOID().equals(
2622 StartTLSExtendedRequest.STARTTLS_REQUEST_OID))
2623 {
2624 startTLSRequest = extendedRequest.duplicate();
2625 }
2626
2627 return extendedResult;
2628 }
2629
2630
2631
2632 /**
2633 * Applies the provided modification to the specified entry.
2634 *
2635 * @param dn The DN of the entry to modify. It must not be {@code null}.
2636 * @param mod The modification to apply to the target entry. It must not
2637 * be {@code null}.
2638 *
2639 * @return The result of processing the modify operation.
2640 *
2641 * @throws LDAPException If the server rejects the modify request, or if a
2642 * problem is encountered while sending the request or
2643 * reading the response.
2644 */
2645 public LDAPResult modify(final String dn, final Modification mod)
2646 throws LDAPException
2647 {
2648 ensureNotNull(dn, mod);
2649
2650 return modify(new ModifyRequest(dn, mod));
2651 }
2652
2653
2654
2655 /**
2656 * Applies the provided set of modifications to the specified entry.
2657 *
2658 * @param dn The DN of the entry to modify. It must not be {@code null}.
2659 * @param mods The set of modifications to apply to the target entry. It
2660 * must not be {@code null} or empty. *
2661 * @return The result of processing the modify operation.
2662 *
2663 * @throws LDAPException If the server rejects the modify request, or if a
2664 * problem is encountered while sending the request or
2665 * reading the response.
2666 */
2667 public LDAPResult modify(final String dn, final Modification... mods)
2668 throws LDAPException
2669 {
2670 ensureNotNull(dn, mods);
2671
2672 return modify(new ModifyRequest(dn, mods));
2673 }
2674
2675
2676
2677 /**
2678 * Applies the provided set of modifications to the specified entry.
2679 *
2680 * @param dn The DN of the entry to modify. It must not be {@code null}.
2681 * @param mods The set of modifications to apply to the target entry. It
2682 * must not be {@code null} or empty.
2683 *
2684 * @return The result of processing the modify operation.
2685 *
2686 * @throws LDAPException If the server rejects the modify request, or if a
2687 * problem is encountered while sending the request or
2688 * reading the response.
2689 */
2690 public LDAPResult modify(final String dn, final List<Modification> mods)
2691 throws LDAPException
2692 {
2693 ensureNotNull(dn, mods);
2694
2695 return modify(new ModifyRequest(dn, mods));
2696 }
2697
2698
2699
2700 /**
2701 * Processes a modify request from the provided LDIF representation of the
2702 * changes.
2703 *
2704 * @param ldifModificationLines The lines that comprise an LDIF
2705 * representation of a modify change record.
2706 * It must not be {@code null} or empty.
2707 *
2708 * @return The result of processing the modify operation.
2709 *
2710 * @throws LDIFException If the provided set of lines cannot be parsed as an
2711 * LDIF modify change record.
2712 *
2713 * @throws LDAPException If the server rejects the modify request, or if a
2714 * problem is encountered while sending the request or
2715 * reading the response.
2716 *
2717 */
2718 public LDAPResult modify(final String... ldifModificationLines)
2719 throws LDIFException, LDAPException
2720 {
2721 ensureNotNull(ldifModificationLines);
2722
2723 return modify(new ModifyRequest(ldifModificationLines));
2724 }
2725
2726
2727
2728 /**
2729 * Processes the provided modify request.
2730 *
2731 * @param modifyRequest The modify request to be processed. It must not be
2732 * {@code null}.
2733 *
2734 * @return The result of processing the modify operation.
2735 *
2736 * @throws LDAPException If the server rejects the modify request, or if a
2737 * problem is encountered while sending the request or
2738 * reading the response.
2739 */
2740 public LDAPResult modify(final ModifyRequest modifyRequest)
2741 throws LDAPException
2742 {
2743 ensureNotNull(modifyRequest);
2744
2745 final LDAPResult ldapResult = modifyRequest.process(this, 1);
2746
2747 switch (ldapResult.getResultCode().intValue())
2748 {
2749 case ResultCode.SUCCESS_INT_VALUE:
2750 case ResultCode.NO_OPERATION_INT_VALUE:
2751 return ldapResult;
2752
2753 default:
2754 throw new LDAPException(ldapResult);
2755 }
2756 }
2757
2758
2759
2760 /**
2761 * Processes the provided modify request.
2762 *
2763 * @param modifyRequest The modify request to be processed. It must not be
2764 * {@code null}.
2765 *
2766 * @return The result of processing the modify operation.
2767 *
2768 * @throws LDAPException If the server rejects the modify request, or if a
2769 * problem is encountered while sending the request or
2770 * reading the response.
2771 */
2772 public LDAPResult modify(final ReadOnlyModifyRequest modifyRequest)
2773 throws LDAPException
2774 {
2775 return modify((ModifyRequest) modifyRequest);
2776 }
2777
2778
2779
2780 /**
2781 * Processes the provided modify request as an asynchronous operation.
2782 *
2783 * @param modifyRequest The modify request to be processed. It must not be
2784 * {@code null}.
2785 * @param resultListener The async result listener to use to handle the
2786 * response for the modify operation. It may be
2787 * {@code null} if the result is going to be obtained
2788 * from the returned {@code AsyncRequestID} object via
2789 * the {@code Future} API.
2790 *
2791 * @return An async request ID that may be used to reference the operation.
2792 *
2793 * @throws LDAPException If a problem occurs while sending the request.
2794 */
2795 public AsyncRequestID asyncModify(final ModifyRequest modifyRequest,
2796 final AsyncResultListener resultListener)
2797 throws LDAPException
2798 {
2799 ensureNotNull(modifyRequest);
2800
2801 if (synchronousMode())
2802 {
2803 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2804 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2805 }
2806
2807 final AsyncResultListener listener;
2808 if (resultListener == null)
2809 {
2810 listener = DiscardAsyncListener.getInstance();
2811 }
2812 else
2813 {
2814 listener = resultListener;
2815 }
2816
2817 return modifyRequest.processAsync(this, listener);
2818 }
2819
2820
2821
2822 /**
2823 * Processes the provided modify request as an asynchronous operation.
2824 *
2825 * @param modifyRequest The modify request to be processed. It must not be
2826 * {@code null}.
2827 * @param resultListener The async result listener to use to handle the
2828 * response for the modify operation. It may be
2829 * {@code null} if the result is going to be obtained
2830 * from the returned {@code AsyncRequestID} object via
2831 * the {@code Future} API.
2832 *
2833 * @return An async request ID that may be used to reference the operation.
2834 *
2835 * @throws LDAPException If a problem occurs while sending the request.
2836 */
2837 public AsyncRequestID asyncModify(final ReadOnlyModifyRequest modifyRequest,
2838 final AsyncResultListener resultListener)
2839 throws LDAPException
2840 {
2841 if (synchronousMode())
2842 {
2843 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2844 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2845 }
2846
2847 return asyncModify((ModifyRequest) modifyRequest, resultListener);
2848 }
2849
2850
2851
2852 /**
2853 * Performs a modify DN operation with the provided information.
2854 *
2855 * @param dn The current DN for the entry to rename. It must not
2856 * be {@code null}.
2857 * @param newRDN The new RDN to use for the entry. It must not be
2858 * {@code null}.
2859 * @param deleteOldRDN Indicates whether to delete the current RDN value
2860 * from the entry.
2861 *
2862 * @return The result of processing the modify DN operation.
2863 *
2864 * @throws LDAPException If the server rejects the modify DN request, or if
2865 * a problem is encountered while sending the request
2866 * or reading the response.
2867 */
2868 public LDAPResult modifyDN(final String dn, final String newRDN,
2869 final boolean deleteOldRDN)
2870 throws LDAPException
2871 {
2872 ensureNotNull(dn, newRDN);
2873
2874 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN));
2875 }
2876
2877
2878
2879 /**
2880 * Performs a modify DN operation with the provided information.
2881 *
2882 * @param dn The current DN for the entry to rename. It must not
2883 * be {@code null}.
2884 * @param newRDN The new RDN to use for the entry. It must not be
2885 * {@code null}.
2886 * @param deleteOldRDN Indicates whether to delete the current RDN value
2887 * from the entry.
2888 * @param newSuperiorDN The new superior DN for the entry. It may be
2889 * {@code null} if the entry is not to be moved below a
2890 * new parent.
2891 *
2892 * @return The result of processing the modify DN operation.
2893 *
2894 * @throws LDAPException If the server rejects the modify DN request, or if
2895 * a problem is encountered while sending the request
2896 * or reading the response.
2897 */
2898 public LDAPResult modifyDN(final String dn, final String newRDN,
2899 final boolean deleteOldRDN,
2900 final String newSuperiorDN)
2901 throws LDAPException
2902 {
2903 ensureNotNull(dn, newRDN);
2904
2905 return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN,
2906 newSuperiorDN));
2907 }
2908
2909
2910
2911 /**
2912 * Processes the provided modify DN request.
2913 *
2914 * @param modifyDNRequest The modify DN request to be processed. It must
2915 * not be {@code null}.
2916 *
2917 * @return The result of processing the modify DN operation.
2918 *
2919 * @throws LDAPException If the server rejects the modify DN request, or if
2920 * a problem is encountered while sending the request
2921 * or reading the response.
2922 */
2923 public LDAPResult modifyDN(final ModifyDNRequest modifyDNRequest)
2924 throws LDAPException
2925 {
2926 ensureNotNull(modifyDNRequest);
2927
2928 final LDAPResult ldapResult = modifyDNRequest.process(this, 1);
2929
2930 switch (ldapResult.getResultCode().intValue())
2931 {
2932 case ResultCode.SUCCESS_INT_VALUE:
2933 case ResultCode.NO_OPERATION_INT_VALUE:
2934 return ldapResult;
2935
2936 default:
2937 throw new LDAPException(ldapResult);
2938 }
2939 }
2940
2941
2942
2943 /**
2944 * Processes the provided modify DN request.
2945 *
2946 * @param modifyDNRequest The modify DN request to be processed. It must
2947 * not be {@code null}.
2948 *
2949 * @return The result of processing the modify DN operation.
2950 *
2951 * @throws LDAPException If the server rejects the modify DN request, or if
2952 * a problem is encountered while sending the request
2953 * or reading the response.
2954 */
2955 public LDAPResult modifyDN(final ReadOnlyModifyDNRequest modifyDNRequest)
2956 throws LDAPException
2957 {
2958 return modifyDN((ModifyDNRequest) modifyDNRequest);
2959 }
2960
2961
2962
2963 /**
2964 * Processes the provided modify DN request as an asynchronous operation.
2965 *
2966 * @param modifyDNRequest The modify DN request to be processed. It must
2967 * not be {@code null}.
2968 * @param resultListener The async result listener to use to handle the
2969 * response for the modify DN operation. It may be
2970 * {@code null} if the result is going to be obtained
2971 * from the returned {@code AsyncRequestID} object via
2972 * the {@code Future} API.
2973 *
2974 * @return An async request ID that may be used to reference the operation.
2975 *
2976 * @throws LDAPException If a problem occurs while sending the request.
2977 */
2978 public AsyncRequestID asyncModifyDN(final ModifyDNRequest modifyDNRequest,
2979 final AsyncResultListener resultListener)
2980 throws LDAPException
2981 {
2982 ensureNotNull(modifyDNRequest);
2983
2984 if (synchronousMode())
2985 {
2986 throw new LDAPException(ResultCode.NOT_SUPPORTED,
2987 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
2988 }
2989
2990 final AsyncResultListener listener;
2991 if (resultListener == null)
2992 {
2993 listener = DiscardAsyncListener.getInstance();
2994 }
2995 else
2996 {
2997 listener = resultListener;
2998 }
2999
3000 return modifyDNRequest.processAsync(this, listener);
3001 }
3002
3003
3004
3005 /**
3006 * Processes the provided modify DN request as an asynchronous operation.
3007 *
3008 * @param modifyDNRequest The modify DN request to be processed. It must
3009 * not be {@code null}.
3010 * @param resultListener The async result listener to use to handle the
3011 * response for the modify DN operation. It may be
3012 * {@code null} if the result is going to be obtained
3013 * from the returned {@code AsyncRequestID} object via
3014 * the {@code Future} API.
3015 *
3016 * @return An async request ID that may be used to reference the operation.
3017 *
3018 * @throws LDAPException If a problem occurs while sending the request.
3019 */
3020 public AsyncRequestID asyncModifyDN(
3021 final ReadOnlyModifyDNRequest modifyDNRequest,
3022 final AsyncResultListener resultListener)
3023 throws LDAPException
3024 {
3025 if (synchronousMode())
3026 {
3027 throw new LDAPException(ResultCode.NOT_SUPPORTED,
3028 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
3029 }
3030
3031 return asyncModifyDN((ModifyDNRequest) modifyDNRequest, resultListener);
3032 }
3033
3034
3035
3036 /**
3037 * Processes a search operation with the provided information. The search
3038 * result entries and references will be collected internally and included in
3039 * the {@code SearchResult} object that is returned.
3040 * <BR><BR>
3041 * Note that if the search does not complete successfully, an
3042 * {@code LDAPSearchException} will be thrown In some cases, one or more
3043 * search result entries or references may have been returned before the
3044 * failure response is received. In this case, the
3045 * {@code LDAPSearchException} methods like {@code getEntryCount},
3046 * {@code getSearchEntries}, {@code getReferenceCount}, and
3047 * {@code getSearchReferences} may be used to obtain information about those
3048 * entries and references.
3049 *
3050 * @param baseDN The base DN for the search request. It must not be
3051 * {@code null}.
3052 * @param scope The scope that specifies the range of entries that
3053 * should be examined for the search.
3054 * @param filter The string representation of the filter to use to
3055 * identify matching entries. It must not be
3056 * {@code null}.
3057 * @param attributes The set of attributes that should be returned in
3058 * matching entries. It may be {@code null} or empty if
3059 * the default attribute set (all user attributes) is to
3060 * be requested.
3061 *
3062 * @return A search result object that provides information about the
3063 * processing of the search, including the set of matching entries
3064 * and search references returned by the server.
3065 *
3066 * @throws LDAPSearchException If the search does not complete successfully,
3067 * or if a problem is encountered while parsing
3068 * the provided filter string, sending the
3069 * request, or reading the response. If one
3070 * or more entries or references were returned
3071 * before the failure was encountered, then the
3072 * {@code LDAPSearchException} object may be
3073 * examined to obtain information about those
3074 * entries and/or references.
3075 */
3076 public SearchResult search(final String baseDN, final SearchScope scope,
3077 final String filter, final String... attributes)
3078 throws LDAPSearchException
3079 {
3080 ensureNotNull(baseDN, filter);
3081
3082 try
3083 {
3084 return search(new SearchRequest(baseDN, scope, filter, attributes));
3085 }
3086 catch (LDAPSearchException lse)
3087 {
3088 debugException(lse);
3089 throw lse;
3090 }
3091 catch (LDAPException le)
3092 {
3093 debugException(le);
3094 throw new LDAPSearchException(le);
3095 }
3096 }
3097
3098
3099
3100 /**
3101 * Processes a search operation with the provided information. The search
3102 * result entries and references will be collected internally and included in
3103 * the {@code SearchResult} object that is returned.
3104 * <BR><BR>
3105 * Note that if the search does not complete successfully, an
3106 * {@code LDAPSearchException} will be thrown In some cases, one or more
3107 * search result entries or references may have been returned before the
3108 * failure response is received. In this case, the
3109 * {@code LDAPSearchException} methods like {@code getEntryCount},
3110 * {@code getSearchEntries}, {@code getReferenceCount}, and
3111 * {@code getSearchReferences} may be used to obtain information about those
3112 * entries and references.
3113 *
3114 * @param baseDN The base DN for the search request. It must not be
3115 * {@code null}.
3116 * @param scope The scope that specifies the range of entries that
3117 * should be examined for the search.
3118 * @param filter The filter to use to identify matching entries. It
3119 * must not be {@code null}.
3120 * @param attributes The set of attributes that should be returned in
3121 * matching entries. It may be {@code null} or empty if
3122 * the default attribute set (all user attributes) is to
3123 * be requested.
3124 *
3125 * @return A search result object that provides information about the
3126 * processing of the search, including the set of matching entries
3127 * and search references returned by the server.
3128 *
3129 * @throws LDAPSearchException If the search does not complete successfully,
3130 * or if a problem is encountered while sending
3131 * the request or reading the response. If one
3132 * or more entries or references were returned
3133 * before the failure was encountered, then the
3134 * {@code LDAPSearchException} object may be
3135 * examined to obtain information about those
3136 * entries and/or references.
3137 */
3138 public SearchResult search(final String baseDN, final SearchScope scope,
3139 final Filter filter, final String... attributes)
3140 throws LDAPSearchException
3141 {
3142 ensureNotNull(baseDN, filter);
3143
3144 return search(new SearchRequest(baseDN, scope, filter, attributes));
3145 }
3146
3147
3148
3149 /**
3150 * Processes a search operation with the provided information.
3151 * <BR><BR>
3152 * Note that if the search does not complete successfully, an
3153 * {@code LDAPSearchException} will be thrown In some cases, one or more
3154 * search result entries or references may have been returned before the
3155 * failure response is received. In this case, the
3156 * {@code LDAPSearchException} methods like {@code getEntryCount},
3157 * {@code getSearchEntries}, {@code getReferenceCount}, and
3158 * {@code getSearchReferences} may be used to obtain information about those
3159 * entries and references (although if a search result listener was provided,
3160 * then it will have been used to make any entries and references available,
3161 * and they will not be available through the {@code getSearchEntries} and
3162 * {@code getSearchReferences} methods).
3163 *
3164 * @param searchResultListener The search result listener that should be
3165 * used to return results to the client. It may
3166 * be {@code null} if the search results should
3167 * be collected internally and returned in the
3168 * {@code SearchResult} object.
3169 * @param baseDN The base DN for the search request. It must
3170 * not be {@code null}.
3171 * @param scope The scope that specifies the range of entries
3172 * that should be examined for the search.
3173 * @param filter The string representation of the filter to
3174 * use to identify matching entries. It must
3175 * not be {@code null}.
3176 * @param attributes The set of attributes that should be returned
3177 * in matching entries. It may be {@code null}
3178 * or empty if the default attribute set (all
3179 * user attributes) is to be requested.
3180 *
3181 * @return A search result object that provides information about the
3182 * processing of the search, potentially including the set of
3183 * matching entries and search references returned by the server.
3184 *
3185 * @throws LDAPSearchException If the search does not complete successfully,
3186 * or if a problem is encountered while parsing
3187 * the provided filter string, sending the
3188 * request, or reading the response. If one
3189 * or more entries or references were returned
3190 * before the failure was encountered, then the
3191 * {@code LDAPSearchException} object may be
3192 * examined to obtain information about those
3193 * entries and/or references.
3194 */
3195 public SearchResult search(final SearchResultListener searchResultListener,
3196 final String baseDN, final SearchScope scope,
3197 final String filter, final String... attributes)
3198 throws LDAPSearchException
3199 {
3200 ensureNotNull(baseDN, filter);
3201
3202 try
3203 {
3204 return search(new SearchRequest(searchResultListener, baseDN, scope,
3205 filter, attributes));
3206 }
3207 catch (LDAPSearchException lse)
3208 {
3209 debugException(lse);
3210 throw lse;
3211 }
3212 catch (LDAPException le)
3213 {
3214 debugException(le);
3215 throw new LDAPSearchException(le);
3216 }
3217 }
3218
3219
3220
3221 /**
3222 * Processes a search operation with the provided information.
3223 * <BR><BR>
3224 * Note that if the search does not complete successfully, an
3225 * {@code LDAPSearchException} will be thrown In some cases, one or more
3226 * search result entries or references may have been returned before the
3227 * failure response is received. In this case, the
3228 * {@code LDAPSearchException} methods like {@code getEntryCount},
3229 * {@code getSearchEntries}, {@code getReferenceCount}, and
3230 * {@code getSearchReferences} may be used to obtain information about those
3231 * entries and references (although if a search result listener was provided,
3232 * then it will have been used to make any entries and references available,
3233 * and they will not be available through the {@code getSearchEntries} and
3234 * {@code getSearchReferences} methods).
3235 *
3236 * @param searchResultListener The search result listener that should be
3237 * used to return results to the client. It may
3238 * be {@code null} if the search results should
3239 * be collected internally and returned in the
3240 * {@code SearchResult} object.
3241 * @param baseDN The base DN for the search request. It must
3242 * not be {@code null}.
3243 * @param scope The scope that specifies the range of entries
3244 * that should be examined for the search.
3245 * @param filter The filter to use to identify matching
3246 * entries. It must not be {@code null}.
3247 * @param attributes The set of attributes that should be returned
3248 * in matching entries. It may be {@code null}
3249 * or empty if the default attribute set (all
3250 * user attributes) is to be requested.
3251 *
3252 * @return A search result object that provides information about the
3253 * processing of the search, potentially including the set of
3254 * matching entries and search references returned by the server.
3255 *
3256 * @throws LDAPSearchException If the search does not complete successfully,
3257 * or if a problem is encountered while sending
3258 * the request or reading the response. If one
3259 * or more entries or references were returned
3260 * before the failure was encountered, then the
3261 * {@code LDAPSearchException} object may be
3262 * examined to obtain information about those
3263 * entries and/or references.
3264 */
3265 public SearchResult search(final SearchResultListener searchResultListener,
3266 final String baseDN, final SearchScope scope,
3267 final Filter filter, final String... attributes)
3268 throws LDAPSearchException
3269 {
3270 ensureNotNull(baseDN, filter);
3271
3272 try
3273 {
3274 return search(new SearchRequest(searchResultListener, baseDN, scope,
3275 filter, attributes));
3276 }
3277 catch (LDAPSearchException lse)
3278 {
3279 debugException(lse);
3280 throw lse;
3281 }
3282 catch (LDAPException le)
3283 {
3284 debugException(le);
3285 throw new LDAPSearchException(le);
3286 }
3287 }
3288
3289
3290
3291 /**
3292 * Processes a search operation with the provided information. The search
3293 * result entries and references will be collected internally and included in
3294 * the {@code SearchResult} object that is returned.
3295 * <BR><BR>
3296 * Note that if the search does not complete successfully, an
3297 * {@code LDAPSearchException} will be thrown In some cases, one or more
3298 * search result entries or references may have been returned before the
3299 * failure response is received. In this case, the
3300 * {@code LDAPSearchException} methods like {@code getEntryCount},
3301 * {@code getSearchEntries}, {@code getReferenceCount}, and
3302 * {@code getSearchReferences} may be used to obtain information about those
3303 * entries and references.
3304 *
3305 * @param baseDN The base DN for the search request. It must not be
3306 * {@code null}.
3307 * @param scope The scope that specifies the range of entries that
3308 * should be examined for the search.
3309 * @param derefPolicy The dereference policy the server should use for any
3310 * aliases encountered while processing the search.
3311 * @param sizeLimit The maximum number of entries that the server should
3312 * return for the search. A value of zero indicates that
3313 * there should be no limit.
3314 * @param timeLimit The maximum length of time in seconds that the server
3315 * should spend processing this search request. A value
3316 * of zero indicates that there should be no limit.
3317 * @param typesOnly Indicates whether to return only attribute names in
3318 * matching entries, or both attribute names and values.
3319 * @param filter The string representation of the filter to use to
3320 * identify matching entries. It must not be
3321 * {@code null}.
3322 * @param attributes The set of attributes that should be returned in
3323 * matching entries. It may be {@code null} or empty if
3324 * the default attribute set (all user attributes) is to
3325 * be requested.
3326 *
3327 * @return A search result object that provides information about the
3328 * processing of the search, including the set of matching entries
3329 * and search references returned by the server.
3330 *
3331 * @throws LDAPSearchException If the search does not complete successfully,
3332 * or if a problem is encountered while parsing
3333 * the provided filter string, sending the
3334 * request, or reading the response. If one
3335 * or more entries or references were returned
3336 * before the failure was encountered, then the
3337 * {@code LDAPSearchException} object may be
3338 * examined to obtain information about those
3339 * entries and/or references.
3340 */
3341 public SearchResult search(final String baseDN, final SearchScope scope,
3342 final DereferencePolicy derefPolicy,
3343 final int sizeLimit, final int timeLimit,
3344 final boolean typesOnly, final String filter,
3345 final String... attributes)
3346 throws LDAPSearchException
3347 {
3348 ensureNotNull(baseDN, filter);
3349
3350 try
3351 {
3352 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit,
3353 timeLimit, typesOnly, filter,
3354 attributes));
3355 }
3356 catch (LDAPSearchException lse)
3357 {
3358 debugException(lse);
3359 throw lse;
3360 }
3361 catch (LDAPException le)
3362 {
3363 debugException(le);
3364 throw new LDAPSearchException(le);
3365 }
3366 }
3367
3368
3369
3370 /**
3371 * Processes a search operation with the provided information. The search
3372 * result entries and references will be collected internally and included in
3373 * the {@code SearchResult} object that is returned.
3374 * <BR><BR>
3375 * Note that if the search does not complete successfully, an
3376 * {@code LDAPSearchException} will be thrown In some cases, one or more
3377 * search result entries or references may have been returned before the
3378 * failure response is received. In this case, the
3379 * {@code LDAPSearchException} methods like {@code getEntryCount},
3380 * {@code getSearchEntries}, {@code getReferenceCount}, and
3381 * {@code getSearchReferences} may be used to obtain information about those
3382 * entries and references.
3383 *
3384 * @param baseDN The base DN for the search request. It must not be
3385 * {@code null}.
3386 * @param scope The scope that specifies the range of entries that
3387 * should be examined for the search.
3388 * @param derefPolicy The dereference policy the server should use for any
3389 * aliases encountered while processing the search.
3390 * @param sizeLimit The maximum number of entries that the server should
3391 * return for the search. A value of zero indicates that
3392 * there should be no limit.
3393 * @param timeLimit The maximum length of time in seconds that the server
3394 * should spend processing this search request. A value
3395 * of zero indicates that there should be no limit.
3396 * @param typesOnly Indicates whether to return only attribute names in
3397 * matching entries, or both attribute names and values.
3398 * @param filter The filter to use to identify matching entries. It
3399 * must not be {@code null}.
3400 * @param attributes The set of attributes that should be returned in
3401 * matching entries. It may be {@code null} or empty if
3402 * the default attribute set (all user attributes) is to
3403 * be requested.
3404 *
3405 * @return A search result object that provides information about the
3406 * processing of the search, including the set of matching entries
3407 * and search references returned by the server.
3408 *
3409 * @throws LDAPSearchException If the search does not complete successfully,
3410 * or if a problem is encountered while sending
3411 * the request or reading the response. If one
3412 * or more entries or references were returned
3413 * before the failure was encountered, then the
3414 * {@code LDAPSearchException} object may be
3415 * examined to obtain information about those
3416 * entries and/or references.
3417 */
3418 public SearchResult search(final String baseDN, final SearchScope scope,
3419 final DereferencePolicy derefPolicy,
3420 final int sizeLimit, final int timeLimit,
3421 final boolean typesOnly, final Filter filter,
3422 final String... attributes)
3423 throws LDAPSearchException
3424 {
3425 ensureNotNull(baseDN, filter);
3426
3427 return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit,
3428 timeLimit, typesOnly, filter, attributes));
3429 }
3430
3431
3432
3433 /**
3434 * Processes a search operation with the provided information.
3435 * <BR><BR>
3436 * Note that if the search does not complete successfully, an
3437 * {@code LDAPSearchException} will be thrown In some cases, one or more
3438 * search result entries or references may have been returned before the
3439 * failure response is received. In this case, the
3440 * {@code LDAPSearchException} methods like {@code getEntryCount},
3441 * {@code getSearchEntries}, {@code getReferenceCount}, and
3442 * {@code getSearchReferences} may be used to obtain information about those
3443 * entries and references (although if a search result listener was provided,
3444 * then it will have been used to make any entries and references available,
3445 * and they will not be available through the {@code getSearchEntries} and
3446 * {@code getSearchReferences} methods).
3447 *
3448 * @param searchResultListener The search result listener that should be
3449 * used to return results to the client. It may
3450 * be {@code null} if the search results should
3451 * be collected internally and returned in the
3452 * {@code SearchResult} object.
3453 * @param baseDN The base DN for the search request. It must
3454 * not be {@code null}.
3455 * @param scope The scope that specifies the range of entries
3456 * that should be examined for the search.
3457 * @param derefPolicy The dereference policy the server should use
3458 * for any aliases encountered while processing
3459 * the search.
3460 * @param sizeLimit The maximum number of entries that the server
3461 * should return for the search. A value of
3462 * zero indicates that there should be no limit.
3463 * @param timeLimit The maximum length of time in seconds that
3464 * the server should spend processing this
3465 * search request. A value of zero indicates
3466 * that there should be no limit.
3467 * @param typesOnly Indicates whether to return only attribute
3468 * names in matching entries, or both attribute
3469 * names and values.
3470 * @param filter The string representation of the filter to
3471 * use to identify matching entries. It must
3472 * not be {@code null}.
3473 * @param attributes The set of attributes that should be returned
3474 * in matching entries. It may be {@code null}
3475 * or empty if the default attribute set (all
3476 * user attributes) is to be requested.
3477 *
3478 * @return A search result object that provides information about the
3479 * processing of the search, potentially including the set of
3480 * matching entries and search references returned by the server.
3481 *
3482 * @throws LDAPSearchException If the search does not complete successfully,
3483 * or if a problem is encountered while parsing
3484 * the provided filter string, sending the
3485 * request, or reading the response. If one
3486 * or more entries or references were returned
3487 * before the failure was encountered, then the
3488 * {@code LDAPSearchException} object may be
3489 * examined to obtain information about those
3490 * entries and/or references.
3491 */
3492 public SearchResult search(final SearchResultListener searchResultListener,
3493 final String baseDN, final SearchScope scope,
3494 final DereferencePolicy derefPolicy,
3495 final int sizeLimit, final int timeLimit,
3496 final boolean typesOnly, final String filter,
3497 final String... attributes)
3498 throws LDAPSearchException
3499 {
3500 ensureNotNull(baseDN, filter);
3501
3502 try
3503 {
3504 return search(new SearchRequest(searchResultListener, baseDN, scope,
3505 derefPolicy, sizeLimit, timeLimit,
3506 typesOnly, filter, attributes));
3507 }
3508 catch (LDAPSearchException lse)
3509 {
3510 debugException(lse);
3511 throw lse;
3512 }
3513 catch (LDAPException le)
3514 {
3515 debugException(le);
3516 throw new LDAPSearchException(le);
3517 }
3518 }
3519
3520
3521
3522 /**
3523 * Processes a search operation with the provided information.
3524 * <BR><BR>
3525 * Note that if the search does not complete successfully, an
3526 * {@code LDAPSearchException} will be thrown In some cases, one or more
3527 * search result entries or references may have been returned before the
3528 * failure response is received. In this case, the
3529 * {@code LDAPSearchException} methods like {@code getEntryCount},
3530 * {@code getSearchEntries}, {@code getReferenceCount}, and
3531 * {@code getSearchReferences} may be used to obtain information about those
3532 * entries and references (although if a search result listener was provided,
3533 * then it will have been used to make any entries and references available,
3534 * and they will not be available through the {@code getSearchEntries} and
3535 * {@code getSearchReferences} methods).
3536 *
3537 * @param searchResultListener The search result listener that should be
3538 * used to return results to the client. It may
3539 * be {@code null} if the search results should
3540 * be collected internally and returned in the
3541 * {@code SearchResult} object.
3542 * @param baseDN The base DN for the search request. It must
3543 * not be {@code null}.
3544 * @param scope The scope that specifies the range of entries
3545 * that should be examined for the search.
3546 * @param derefPolicy The dereference policy the server should use
3547 * for any aliases encountered while processing
3548 * the search.
3549 * @param sizeLimit The maximum number of entries that the server
3550 * should return for the search. A value of
3551 * zero indicates that there should be no limit.
3552 * @param timeLimit The maximum length of time in seconds that
3553 * the server should spend processing this
3554 * search request. A value of zero indicates
3555 * that there should be no limit.
3556 * @param typesOnly Indicates whether to return only attribute
3557 * names in matching entries, or both attribute
3558 * names and values.
3559 * @param filter The filter to use to identify matching
3560 * entries. It must not be {@code null}.
3561 * @param attributes The set of attributes that should be returned
3562 * in matching entries. It may be {@code null}
3563 * or empty if the default attribute set (all
3564 * user attributes) is to be requested.
3565 *
3566 * @return A search result object that provides information about the
3567 * processing of the search, potentially including the set of
3568 * matching entries and search references returned by the server.
3569 *
3570 * @throws LDAPSearchException If the search does not complete successfully,
3571 * or if a problem is encountered while sending
3572 * the request or reading the response. If one
3573 * or more entries or references were returned
3574 * before the failure was encountered, then the
3575 * {@code LDAPSearchException} object may be
3576 * examined to obtain information about those
3577 * entries and/or references.
3578 */
3579 public SearchResult search(final SearchResultListener searchResultListener,
3580 final String baseDN, final SearchScope scope,
3581 final DereferencePolicy derefPolicy,
3582 final int sizeLimit, final int timeLimit,
3583 final boolean typesOnly, final Filter filter,
3584 final String... attributes)
3585 throws LDAPSearchException
3586 {
3587 ensureNotNull(baseDN, filter);
3588
3589 return search(new SearchRequest(searchResultListener, baseDN, scope,
3590 derefPolicy, sizeLimit, timeLimit,
3591 typesOnly, filter, attributes));
3592 }
3593
3594
3595
3596 /**
3597 * Processes the provided search request.
3598 * <BR><BR>
3599 * Note that if the search does not complete successfully, an
3600 * {@code LDAPSearchException} will be thrown In some cases, one or more
3601 * search result entries or references may have been returned before the
3602 * failure response is received. In this case, the
3603 * {@code LDAPSearchException} methods like {@code getEntryCount},
3604 * {@code getSearchEntries}, {@code getReferenceCount}, and
3605 * {@code getSearchReferences} may be used to obtain information about those
3606 * entries and references (although if a search result listener was provided,
3607 * then it will have been used to make any entries and references available,
3608 * and they will not be available through the {@code getSearchEntries} and
3609 * {@code getSearchReferences} methods).
3610 *
3611 * @param searchRequest The search request to be processed. It must not be
3612 * {@code null}.
3613 *
3614 * @return A search result object that provides information about the
3615 * processing of the search, potentially including the set of
3616 * matching entries and search references returned by the server.
3617 *
3618 * @throws LDAPSearchException If the search does not complete successfully,
3619 * or if a problem is encountered while sending
3620 * the request or reading the response. If one
3621 * or more entries or references were returned
3622 * before the failure was encountered, then the
3623 * {@code LDAPSearchException} object may be
3624 * examined to obtain information about those
3625 * entries and/or references.
3626 */
3627 public SearchResult search(final SearchRequest searchRequest)
3628 throws LDAPSearchException
3629 {
3630 ensureNotNull(searchRequest);
3631
3632 final SearchResult searchResult;
3633 try
3634 {
3635 searchResult = searchRequest.process(this, 1);
3636 }
3637 catch (LDAPSearchException lse)
3638 {
3639 debugException(lse);
3640 throw lse;
3641 }
3642 catch (LDAPException le)
3643 {
3644 debugException(le);
3645 throw new LDAPSearchException(le);
3646 }
3647
3648 if (! searchResult.getResultCode().equals(ResultCode.SUCCESS))
3649 {
3650 throw new LDAPSearchException(searchResult);
3651 }
3652
3653 return searchResult;
3654 }
3655
3656
3657
3658 /**
3659 * Processes the provided search request.
3660 * <BR><BR>
3661 * Note that if the search does not complete successfully, an
3662 * {@code LDAPSearchException} will be thrown In some cases, one or more
3663 * search result entries or references may have been returned before the
3664 * failure response is received. In this case, the
3665 * {@code LDAPSearchException} methods like {@code getEntryCount},
3666 * {@code getSearchEntries}, {@code getReferenceCount}, and
3667 * {@code getSearchReferences} may be used to obtain information about those
3668 * entries and references (although if a search result listener was provided,
3669 * then it will have been used to make any entries and references available,
3670 * and they will not be available through the {@code getSearchEntries} and
3671 * {@code getSearchReferences} methods).
3672 *
3673 * @param searchRequest The search request to be processed. It must not be
3674 * {@code null}.
3675 *
3676 * @return A search result object that provides information about the
3677 * processing of the search, potentially including the set of
3678 * matching entries and search references returned by the server.
3679 *
3680 * @throws LDAPSearchException If the search does not complete successfully,
3681 * or if a problem is encountered while sending
3682 * the request or reading the response. If one
3683 * or more entries or references were returned
3684 * before the failure was encountered, then the
3685 * {@code LDAPSearchException} object may be
3686 * examined to obtain information about those
3687 * entries and/or references.
3688 */
3689 public SearchResult search(final ReadOnlySearchRequest searchRequest)
3690 throws LDAPSearchException
3691 {
3692 return search((SearchRequest) searchRequest);
3693 }
3694
3695
3696
3697 /**
3698 * Processes a search operation with the provided information. It is expected
3699 * that at most one entry will be returned from the search, and that no
3700 * additional content from the successful search result (e.g., diagnostic
3701 * message or response controls) are needed.
3702 * <BR><BR>
3703 * Note that if the search does not complete successfully, an
3704 * {@code LDAPSearchException} will be thrown In some cases, one or more
3705 * search result entries or references may have been returned before the
3706 * failure response is received. In this case, the
3707 * {@code LDAPSearchException} methods like {@code getEntryCount},
3708 * {@code getSearchEntries}, {@code getReferenceCount}, and
3709 * {@code getSearchReferences} may be used to obtain information about those
3710 * entries and references.
3711 *
3712 * @param baseDN The base DN for the search request. It must not be
3713 * {@code null}.
3714 * @param scope The scope that specifies the range of entries that
3715 * should be examined for the search.
3716 * @param filter The string representation of the filter to use to
3717 * identify matching entries. It must not be
3718 * {@code null}.
3719 * @param attributes The set of attributes that should be returned in
3720 * matching entries. It may be {@code null} or empty if
3721 * the default attribute set (all user attributes) is to
3722 * be requested.
3723 *
3724 * @return The entry that was returned from the search, or {@code null} if no
3725 * entry was returned or the base entry does not exist.
3726 *
3727 * @throws LDAPSearchException If the search does not complete successfully,
3728 * if more than a single entry is returned, or
3729 * if a problem is encountered while parsing the
3730 * provided filter string, sending the request,
3731 * or reading the response. If one or more
3732 * entries or references were returned before
3733 * the failure was encountered, then the
3734 * {@code LDAPSearchException} object may be
3735 * examined to obtain information about those
3736 * entries and/or references.
3737 */
3738 public SearchResultEntry searchForEntry(final String baseDN,
3739 final SearchScope scope,
3740 final String filter,
3741 final String... attributes)
3742 throws LDAPSearchException
3743 {
3744 final SearchRequest r;
3745 try
3746 {
3747 r = new SearchRequest(baseDN, scope, DereferencePolicy.NEVER, 1, 0, false,
3748 filter, attributes);
3749 }
3750 catch (final LDAPException le)
3751 {
3752 debugException(le);
3753 throw new LDAPSearchException(le);
3754 }
3755
3756 return searchForEntry(r);
3757 }
3758
3759
3760
3761 /**
3762 * Processes a search operation with the provided information. It is expected
3763 * that at most one entry will be returned from the search, and that no
3764 * additional content from the successful search result (e.g., diagnostic
3765 * message or response controls) are needed.
3766 * <BR><BR>
3767 * Note that if the search does not complete successfully, an
3768 * {@code LDAPSearchException} will be thrown In some cases, one or more
3769 * search result entries or references may have been returned before the
3770 * failure response is received. In this case, the
3771 * {@code LDAPSearchException} methods like {@code getEntryCount},
3772 * {@code getSearchEntries}, {@code getReferenceCount}, and
3773 * {@code getSearchReferences} may be used to obtain information about those
3774 * entries and references.
3775 *
3776 * @param baseDN The base DN for the search request. It must not be
3777 * {@code null}.
3778 * @param scope The scope that specifies the range of entries that
3779 * should be examined for the search.
3780 * @param filter The string representation of the filter to use to
3781 * identify matching entries. It must not be
3782 * {@code null}.
3783 * @param attributes The set of attributes that should be returned in
3784 * matching entries. It may be {@code null} or empty if
3785 * the default attribute set (all user attributes) is to
3786 * be requested.
3787 *
3788 * @return The entry that was returned from the search, or {@code null} if no
3789 * entry was returned or the base entry does not exist.
3790 *
3791 * @throws LDAPSearchException If the search does not complete successfully,
3792 * if more than a single entry is returned, or
3793 * if a problem is encountered while parsing the
3794 * provided filter string, sending the request,
3795 * or reading the response. If one or more
3796 * entries or references were returned before
3797 * the failure was encountered, then the
3798 * {@code LDAPSearchException} object may be
3799 * examined to obtain information about those
3800 * entries and/or references.
3801 */
3802 public SearchResultEntry searchForEntry(final String baseDN,
3803 final SearchScope scope,
3804 final Filter filter,
3805 final String... attributes)
3806 throws LDAPSearchException
3807 {
3808 return searchForEntry(new SearchRequest(baseDN, scope,
3809 DereferencePolicy.NEVER, 1, 0, false, filter, attributes));
3810 }
3811
3812
3813
3814 /**
3815 * Processes a search operation with the provided information. It is expected
3816 * that at most one entry will be returned from the search, and that no
3817 * additional content from the successful search result (e.g., diagnostic
3818 * message or response controls) are needed.
3819 * <BR><BR>
3820 * Note that if the search does not complete successfully, an
3821 * {@code LDAPSearchException} will be thrown In some cases, one or more
3822 * search result entries or references may have been returned before the
3823 * failure response is received. In this case, the
3824 * {@code LDAPSearchException} methods like {@code getEntryCount},
3825 * {@code getSearchEntries}, {@code getReferenceCount}, and
3826 * {@code getSearchReferences} may be used to obtain information about those
3827 * entries and references.
3828 *
3829 * @param baseDN The base DN for the search request. It must not be
3830 * {@code null}.
3831 * @param scope The scope that specifies the range of entries that
3832 * should be examined for the search.
3833 * @param derefPolicy The dereference policy the server should use for any
3834 * aliases encountered while processing the search.
3835 * @param timeLimit The maximum length of time in seconds that the server
3836 * should spend processing this search request. A value
3837 * of zero indicates that there should be no limit.
3838 * @param typesOnly Indicates whether to return only attribute names in
3839 * matching entries, or both attribute names and values.
3840 * @param filter The string representation of the filter to use to
3841 * identify matching entries. It must not be
3842 * {@code null}.
3843 * @param attributes The set of attributes that should be returned in
3844 * matching entries. It may be {@code null} or empty if
3845 * the default attribute set (all user attributes) is to
3846 * be requested.
3847 *
3848 * @return The entry that was returned from the search, or {@code null} if no
3849 * entry was returned or the base entry does not exist.
3850 *
3851 * @throws LDAPSearchException If the search does not complete successfully,
3852 * if more than a single entry is returned, or
3853 * if a problem is encountered while parsing the
3854 * provided filter string, sending the request,
3855 * or reading the response. If one or more
3856 * entries or references were returned before
3857 * the failure was encountered, then the
3858 * {@code LDAPSearchException} object may be
3859 * examined to obtain information about those
3860 * entries and/or references.
3861 */
3862 public SearchResultEntry searchForEntry(final String baseDN,
3863 final SearchScope scope,
3864 final DereferencePolicy derefPolicy,
3865 final int timeLimit,
3866 final boolean typesOnly,
3867 final String filter,
3868 final String... attributes)
3869 throws LDAPSearchException
3870 {
3871 final SearchRequest r;
3872 try
3873 {
3874 r = new SearchRequest(baseDN, scope, derefPolicy, 1, timeLimit, typesOnly,
3875 filter, attributes);
3876 }
3877 catch (final LDAPException le)
3878 {
3879 debugException(le);
3880 throw new LDAPSearchException(le);
3881 }
3882
3883 return searchForEntry(r);
3884 }
3885
3886
3887
3888 /**
3889 * Processes a search operation with the provided information. It is expected
3890 * that at most one entry will be returned from the search, and that no
3891 * additional content from the successful search result (e.g., diagnostic
3892 * message or response controls) are needed.
3893 * <BR><BR>
3894 * Note that if the search does not complete successfully, an
3895 * {@code LDAPSearchException} will be thrown In some cases, one or more
3896 * search result entries or references may have been returned before the
3897 * failure response is received. In this case, the
3898 * {@code LDAPSearchException} methods like {@code getEntryCount},
3899 * {@code getSearchEntries}, {@code getReferenceCount}, and
3900 * {@code getSearchReferences} may be used to obtain information about those
3901 * entries and references.
3902 *
3903 * @param baseDN The base DN for the search request. It must not be
3904 * {@code null}.
3905 * @param scope The scope that specifies the range of entries that
3906 * should be examined for the search.
3907 * @param derefPolicy The dereference policy the server should use for any
3908 * aliases encountered while processing the search.
3909 * @param timeLimit The maximum length of time in seconds that the server
3910 * should spend processing this search request. A value
3911 * of zero indicates that there should be no limit.
3912 * @param typesOnly Indicates whether to return only attribute names in
3913 * matching entries, or both attribute names and values.
3914 * @param filter The filter to use to identify matching entries. It
3915 * must not be {@code null}.
3916 * @param attributes The set of attributes that should be returned in
3917 * matching entries. It may be {@code null} or empty if
3918 * the default attribute set (all user attributes) is to
3919 * be requested.
3920 *
3921 * @return The entry that was returned from the search, or {@code null} if no
3922 * entry was returned or the base entry does not exist.
3923 *
3924 * @throws LDAPSearchException If the search does not complete successfully,
3925 * if more than a single entry is returned, or
3926 * if a problem is encountered while parsing the
3927 * provided filter string, sending the request,
3928 * or reading the response. If one or more
3929 * entries or references were returned before
3930 * the failure was encountered, then the
3931 * {@code LDAPSearchException} object may be
3932 * examined to obtain information about those
3933 * entries and/or references.
3934 */
3935 public SearchResultEntry searchForEntry(final String baseDN,
3936 final SearchScope scope,
3937 final DereferencePolicy derefPolicy,
3938 final int timeLimit,
3939 final boolean typesOnly,
3940 final Filter filter,
3941 final String... attributes)
3942 throws LDAPSearchException
3943 {
3944 return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1,
3945 timeLimit, typesOnly, filter, attributes));
3946 }
3947
3948
3949
3950 /**
3951 * Processes the provided search request. It is expected that at most one
3952 * entry will be returned from the search, and that no additional content from
3953 * the successful search result (e.g., diagnostic message or response
3954 * controls) are needed.
3955 * <BR><BR>
3956 * Note that if the search does not complete successfully, an
3957 * {@code LDAPSearchException} will be thrown In some cases, one or more
3958 * search result entries or references may have been returned before the
3959 * failure response is received. In this case, the
3960 * {@code LDAPSearchException} methods like {@code getEntryCount},
3961 * {@code getSearchEntries}, {@code getReferenceCount}, and
3962 * {@code getSearchReferences} may be used to obtain information about those
3963 * entries and references.
3964 *
3965 * @param searchRequest The search request to be processed. If it is
3966 * configured with a search result listener or a size
3967 * limit other than one, then the provided request will
3968 * be duplicated with the appropriate settings.
3969 *
3970 * @return The entry that was returned from the search, or {@code null} if no
3971 * entry was returned or the base entry does not exist.
3972 *
3973 * @throws LDAPSearchException If the search does not complete successfully,
3974 * if more than a single entry is returned, or
3975 * if a problem is encountered while parsing the
3976 * provided filter string, sending the request,
3977 * or reading the response. If one or more
3978 * entries or references were returned before
3979 * the failure was encountered, then the
3980 * {@code LDAPSearchException} object may be
3981 * examined to obtain information about those
3982 * entries and/or references.
3983 */
3984 public SearchResultEntry searchForEntry(final SearchRequest searchRequest)
3985 throws LDAPSearchException
3986 {
3987 final SearchRequest r;
3988 if ((searchRequest.getSearchResultListener() != null) ||
3989 (searchRequest.getSizeLimit() != 1))
3990 {
3991 r = new SearchRequest(searchRequest.getBaseDN(), searchRequest.getScope(),
3992 searchRequest.getDereferencePolicy(), 1,
3993 searchRequest.getTimeLimitSeconds(), searchRequest.typesOnly(),
3994 searchRequest.getFilter(), searchRequest.getAttributes());
3995
3996 r.setFollowReferrals(searchRequest.followReferralsInternal());
3997 r.setResponseTimeoutMillis(searchRequest.getResponseTimeoutMillis(null));
3998
3999 if (searchRequest.hasControl())
4000 {
4001 r.setControlsInternal(searchRequest.getControls());
4002 }
4003 }
4004 else
4005 {
4006 r = searchRequest;
4007 }
4008
4009 final SearchResult result;
4010 try
4011 {
4012 result = search(r);
4013 }
4014 catch (final LDAPSearchException lse)
4015 {
4016 debugException(lse);
4017
4018 if (lse.getResultCode() == ResultCode.NO_SUCH_OBJECT)
4019 {
4020 return null;
4021 }
4022
4023 throw lse;
4024 }
4025
4026 if (result.getEntryCount() == 0)
4027 {
4028 return null;
4029 }
4030 else
4031 {
4032 return result.getSearchEntries().get(0);
4033 }
4034 }
4035
4036
4037
4038 /**
4039 * Processes the provided search request. It is expected that at most one
4040 * entry will be returned from the search, and that no additional content from
4041 * the successful search result (e.g., diagnostic message or response
4042 * controls) are needed.
4043 * <BR><BR>
4044 * Note that if the search does not complete successfully, an
4045 * {@code LDAPSearchException} will be thrown In some cases, one or more
4046 * search result entries or references may have been returned before the
4047 * failure response is received. In this case, the
4048 * {@code LDAPSearchException} methods like {@code getEntryCount},
4049 * {@code getSearchEntries}, {@code getReferenceCount}, and
4050 * {@code getSearchReferences} may be used to obtain information about those
4051 * entries and references.
4052 *
4053 * @param searchRequest The search request to be processed. If it is
4054 * configured with a search result listener or a size
4055 * limit other than one, then the provided request will
4056 * be duplicated with the appropriate settings.
4057 *
4058 * @return The entry that was returned from the search, or {@code null} if no
4059 * entry was returned or the base entry does not exist.
4060 *
4061 * @throws LDAPSearchException If the search does not complete successfully,
4062 * if more than a single entry is returned, or
4063 * if a problem is encountered while parsing the
4064 * provided filter string, sending the request,
4065 * or reading the response. If one or more
4066 * entries or references were returned before
4067 * the failure was encountered, then the
4068 * {@code LDAPSearchException} object may be
4069 * examined to obtain information about those
4070 * entries and/or references.
4071 */
4072 public SearchResultEntry searchForEntry(
4073 final ReadOnlySearchRequest searchRequest)
4074 throws LDAPSearchException
4075 {
4076 return searchForEntry((SearchRequest) searchRequest);
4077 }
4078
4079
4080
4081 /**
4082 * Processes the provided search request as an asynchronous operation.
4083 *
4084 * @param searchRequest The search request to be processed. It must not be
4085 * {@code null}, and it must be configured with a
4086 * search result listener that is also an
4087 * {@code AsyncSearchResultListener}.
4088 *
4089 * @return An async request ID that may be used to reference the operation.
4090 *
4091 * @throws LDAPException If the provided search request does not have a
4092 * search result listener that is an
4093 * {@code AsyncSearchResultListener}, or if a problem
4094 * occurs while sending the request.
4095 */
4096 public AsyncRequestID asyncSearch(final SearchRequest searchRequest)
4097 throws LDAPException
4098 {
4099 ensureNotNull(searchRequest);
4100
4101 final SearchResultListener searchListener =
4102 searchRequest.getSearchResultListener();
4103 if (searchListener == null)
4104 {
4105 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR,
4106 ERR_ASYNC_SEARCH_NO_LISTENER.get());
4107 debugCodingError(le);
4108 throw le;
4109 }
4110 else if (! (searchListener instanceof AsyncSearchResultListener))
4111 {
4112 final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR,
4113 ERR_ASYNC_SEARCH_INVALID_LISTENER.get());
4114 debugCodingError(le);
4115 throw le;
4116 }
4117
4118 if (synchronousMode())
4119 {
4120 throw new LDAPException(ResultCode.NOT_SUPPORTED,
4121 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
4122 }
4123
4124 return searchRequest.processAsync(this,
4125 (AsyncSearchResultListener) searchListener);
4126 }
4127
4128
4129
4130 /**
4131 * Processes the provided search request as an asynchronous operation.
4132 *
4133 * @param searchRequest The search request to be processed. It must not be
4134 * {@code null}, and it must be configured with a
4135 * search result listener that is also an
4136 * {@code AsyncSearchResultListener}.
4137 *
4138 * @return An async request ID that may be used to reference the operation.
4139 *
4140 * @throws LDAPException If the provided search request does not have a
4141 * search result listener that is an
4142 * {@code AsyncSearchResultListener}, or if a problem
4143 * occurs while sending the request.
4144 */
4145 public AsyncRequestID asyncSearch(final ReadOnlySearchRequest searchRequest)
4146 throws LDAPException
4147 {
4148 if (synchronousMode())
4149 {
4150 throw new LDAPException(ResultCode.NOT_SUPPORTED,
4151 ERR_ASYNC_NOT_SUPPORTED_IN_SYNCHRONOUS_MODE.get());
4152 }
4153
4154 return asyncSearch((SearchRequest) searchRequest);
4155 }
4156
4157
4158
4159 /**
4160 * Processes the provided generic request and returns the result. This may
4161 * be useful for cases in which it is not known what type of operation the
4162 * request represents.
4163 *
4164 * @param request The request to be processed.
4165 *
4166 * @return The result obtained from processing the request.
4167 *
4168 * @throws LDAPException If a problem occurs while sending the request or
4169 * reading the response. Note simply having a
4170 * non-success result code in the response will not
4171 * cause an exception to be thrown.
4172 */
4173 public LDAPResult processOperation(final LDAPRequest request)
4174 throws LDAPException
4175 {
4176 return request.process(this, 1);
4177 }
4178
4179
4180
4181 /**
4182 * Retrieves the referral connector that should be used to establish
4183 * connections for use when following referrals.
4184 *
4185 * @return The referral connector that should be used to establish
4186 * connections for use when following referrals.
4187 */
4188 public ReferralConnector getReferralConnector()
4189 {
4190 if (referralConnector == null)
4191 {
4192 return this;
4193 }
4194 else
4195 {
4196 return referralConnector;
4197 }
4198 }
4199
4200
4201
4202 /**
4203 * Specifies the referral connector that should be used to establish
4204 * connections for use when following referrals.
4205 *
4206 * @param referralConnector The referral connector that should be used to
4207 * establish connections for use when following
4208 * referrals.
4209 */
4210 public void setReferralConnector(final ReferralConnector referralConnector)
4211 {
4212 if (referralConnector == null)
4213 {
4214 this.referralConnector = this;
4215 }
4216 else
4217 {
4218 this.referralConnector = referralConnector;
4219 }
4220 }
4221
4222
4223
4224 /**
4225 * Sends the provided LDAP message to the server over this connection.
4226 *
4227 * @param message The LDAP message to send to the target server.
4228 *
4229 * @throws LDAPException If a problem occurs while sending the request.
4230 */
4231 void sendMessage(final LDAPMessage message)
4232 throws LDAPException
4233 {
4234 if (needsReconnect.compareAndSet(true, false))
4235 {
4236 reconnect();
4237 }
4238
4239 final LDAPConnectionInternals internals = connectionInternals;
4240 if (internals == null)
4241 {
4242 throw new LDAPException(ResultCode.SERVER_DOWN,
4243 ERR_CONN_NOT_ESTABLISHED.get());
4244 }
4245 else
4246 {
4247 @SuppressWarnings("deprecation")
4248 final boolean autoReconnect = connectionOptions.autoReconnect();
4249 internals.sendMessage(message, autoReconnect);
4250 lastCommunicationTime = System.currentTimeMillis();
4251 }
4252 }
4253
4254
4255
4256 /**
4257 * Retrieves the message ID that should be used for the next request sent
4258 * over this connection.
4259 *
4260 * @return The message ID that should be used for the next request sent over
4261 * this connection, or -1 if this connection is not established.
4262 */
4263 int nextMessageID()
4264 {
4265 final LDAPConnectionInternals internals = connectionInternals;
4266 if (internals == null)
4267 {
4268 return -1;
4269 }
4270 else
4271 {
4272 return internals.nextMessageID();
4273 }
4274 }
4275
4276
4277
4278 /**
4279 * Retrieves the disconnect info object for this connection, if available.
4280 *
4281 * @return The disconnect info for this connection, or {@code null} if none
4282 * is set.
4283 */
4284 DisconnectInfo getDisconnectInfo()
4285 {
4286 return disconnectInfo.get();
4287 }
4288
4289
4290
4291 /**
4292 * Sets the disconnect type, message, and cause for this connection, if those
4293 * values have not been previously set. It will not overwrite any values that
4294 * had been previously set.
4295 * <BR><BR>
4296 * This method may be called by code which is not part of the LDAP SDK to
4297 * provide additional information about the reason for the closure. In that
4298 * case, this method must be called before the call to
4299 * {@link LDAPConnection#close}.
4300 *
4301 * @param type The disconnect type. It must not be {@code null}.
4302 * @param message A message providing additional information about the
4303 * disconnect. It may be {@code null} if no message is
4304 * available.
4305 * @param cause The exception that was caught to trigger the disconnect.
4306 * It may be {@code null} if the disconnect was not triggered
4307 * by an exception.
4308 */
4309 public void setDisconnectInfo(final DisconnectType type, final String message,
4310 final Throwable cause)
4311 {
4312 disconnectInfo.compareAndSet(null,
4313 new DisconnectInfo(this, type, message, cause));
4314 }
4315
4316
4317
4318 /**
4319 * Sets the disconnect info for this connection, if it is not already set.
4320 *
4321 * @param info The disconnect info to be set, if it is not already set.
4322 *
4323 * @return The disconnect info set for the connection, whether it was
4324 * previously or newly set.
4325 */
4326 DisconnectInfo setDisconnectInfo(final DisconnectInfo info)
4327 {
4328 disconnectInfo.compareAndSet(null, info);
4329 return disconnectInfo.get();
4330 }
4331
4332
4333
4334 /**
4335 * Retrieves the disconnect type for this connection, if available.
4336 *
4337 * @return The disconnect type for this connection, or {@code null} if no
4338 * disconnect type has been set.
4339 */
4340 public DisconnectType getDisconnectType()
4341 {
4342 final DisconnectInfo di = disconnectInfo.get();
4343 if (di == null)
4344 {
4345 return null;
4346 }
4347 else
4348 {
4349 return di.getType();
4350 }
4351 }
4352
4353
4354
4355 /**
4356 * Retrieves the disconnect message for this connection, which may provide
4357 * additional information about the reason for the disconnect, if available.
4358 *
4359 * @return The disconnect message for this connection, or {@code null} if
4360 * no disconnect message has been set.
4361 */
4362 public String getDisconnectMessage()
4363 {
4364 final DisconnectInfo di = disconnectInfo.get();
4365 if (di == null)
4366 {
4367 return null;
4368 }
4369 else
4370 {
4371 return di.getMessage();
4372 }
4373 }
4374
4375
4376
4377 /**
4378 * Retrieves the disconnect cause for this connection, which is an exception
4379 * or error that triggered the connection termination, if available.
4380 *
4381 * @return The disconnect cause for this connection, or {@code null} if no
4382 * disconnect cause has been set.
4383 */
4384 public Throwable getDisconnectCause()
4385 {
4386 final DisconnectInfo di = disconnectInfo.get();
4387 if (di == null)
4388 {
4389 return null;
4390 }
4391 else
4392 {
4393 return di.getCause();
4394 }
4395 }
4396
4397
4398
4399 /**
4400 * Indicates that this connection has been closed and is no longer available
4401 * for use.
4402 */
4403 void setClosed()
4404 {
4405 needsReconnect.set(false);
4406
4407 if (disconnectInfo.get() == null)
4408 {
4409 try
4410 {
4411 final StackTraceElement[] stackElements =
4412 Thread.currentThread().getStackTrace();
4413 final StackTraceElement[] parentStackElements =
4414 new StackTraceElement[stackElements.length - 1];
4415 System.arraycopy(stackElements, 1, parentStackElements, 0,
4416 parentStackElements.length);
4417
4418 setDisconnectInfo(DisconnectType.OTHER,
4419 ERR_CONN_CLOSED_BY_UNEXPECTED_CALL_PATH.get(
4420 getStackTrace(parentStackElements)),
4421 null);
4422 }
4423 catch (final Exception e)
4424 {
4425 debugException(e);
4426 }
4427 }
4428
4429 connectionStatistics.incrementNumDisconnects();
4430 final LDAPConnectionInternals internals = connectionInternals;
4431 if (internals != null)
4432 {
4433 internals.close();
4434 connectionInternals = null;
4435 }
4436
4437 cachedSchema = null;
4438 lastCommunicationTime = -1L;
4439
4440 synchronized (this)
4441 {
4442 final Timer t = timer;
4443 timer = null;
4444
4445 if (t != null)
4446 {
4447 t.cancel();
4448 }
4449 }
4450 }
4451
4452
4453
4454 /**
4455 * Registers the provided response acceptor with the connection reader.
4456 *
4457 * @param messageID The message ID for which the acceptor is to be
4458 * registered.
4459 * @param responseAcceptor The response acceptor to register.
4460 *
4461 * @throws LDAPException If another message acceptor is already registered
4462 * with the provided message ID.
4463 */
4464 void registerResponseAcceptor(final int messageID,
4465 final ResponseAcceptor responseAcceptor)
4466 throws LDAPException
4467 {
4468 if (needsReconnect.compareAndSet(true, false))
4469 {
4470 reconnect();
4471 }
4472
4473 final LDAPConnectionInternals internals = connectionInternals;
4474 if (internals == null)
4475 {
4476 throw new LDAPException(ResultCode.SERVER_DOWN,
4477 ERR_CONN_NOT_ESTABLISHED.get());
4478 }
4479 else
4480 {
4481 internals.registerResponseAcceptor(messageID, responseAcceptor);
4482 }
4483 }
4484
4485
4486
4487 /**
4488 * Deregisters the response acceptor associated with the provided message ID.
4489 *
4490 * @param messageID The message ID for which to deregister the associated
4491 * response acceptor.
4492 */
4493 void deregisterResponseAcceptor(final int messageID)
4494 {
4495 final LDAPConnectionInternals internals = connectionInternals;
4496 if (internals != null)
4497 {
4498 internals.deregisterResponseAcceptor(messageID);
4499 }
4500 }
4501
4502
4503
4504 /**
4505 * Retrieves a timer for use with this connection, creating one if necessary.
4506 *
4507 * @return A timer for use with this connection.
4508 */
4509 synchronized Timer getTimer()
4510 {
4511 if (timer == null)
4512 {
4513 timer = new Timer("Timer thread for " + toString(), true);
4514 }
4515
4516 return timer;
4517 }
4518
4519
4520
4521 /**
4522 * {@inheritDoc}
4523 */
4524 public LDAPConnection getReferralConnection(final LDAPURL referralURL,
4525 final LDAPConnection connection)
4526 throws LDAPException
4527 {
4528 final String host = referralURL.getHost();
4529 final int port = referralURL.getPort();
4530
4531 BindRequest bindRequest = null;
4532 if (connection.lastBindRequest != null)
4533 {
4534 bindRequest = connection.lastBindRequest.getRebindRequest(host, port);
4535 if (bindRequest == null)
4536 {
4537 throw new LDAPException(ResultCode.REFERRAL,
4538 ERR_CONN_CANNOT_AUTHENTICATE_FOR_REFERRAL.get(
4539 host, port));
4540 }
4541 }
4542
4543 final ExtendedRequest connStartTLSRequest = connection.startTLSRequest;
4544
4545 final LDAPConnection conn = new LDAPConnection(connection.socketFactory,
4546 connection.connectionOptions, host, port);
4547
4548 if (connStartTLSRequest != null)
4549 {
4550 try
4551 {
4552 final ExtendedResult startTLSResult =
4553 conn.processExtendedOperation(connStartTLSRequest);
4554 if (startTLSResult.getResultCode() != ResultCode.SUCCESS)
4555 {
4556 throw new LDAPException(startTLSResult);
4557 }
4558 }
4559 catch (final LDAPException le)
4560 {
4561 debugException(le);
4562 conn.setDisconnectInfo(DisconnectType.SECURITY_PROBLEM, null, le);
4563 conn.close();
4564
4565 throw le;
4566 }
4567 }
4568
4569 if (bindRequest != null)
4570 {
4571 try
4572 {
4573 conn.bind(bindRequest);
4574 }
4575 catch (final LDAPException le)
4576 {
4577 debugException(le);
4578 conn.setDisconnectInfo(DisconnectType.BIND_FAILED, null, le);
4579 conn.close();
4580
4581 throw le;
4582 }
4583 }
4584
4585 return conn;
4586 }
4587
4588
4589
4590 /**
4591 * Retrieves the last successful bind request processed on this connection.
4592 *
4593 * @return The last successful bind request processed on this connection. It
4594 * may be {@code null} if no bind has been performed, or if the last
4595 * bind attempt was not successful.
4596 */
4597 public BindRequest getLastBindRequest()
4598 {
4599 return lastBindRequest;
4600 }
4601
4602
4603
4604 /**
4605 * Retrieves the StartTLS request used to secure this connection.
4606 *
4607 * @return The StartTLS request used to secure this connection, or
4608 * {@code null} if StartTLS has not been used to secure this
4609 * connection.
4610 */
4611 public ExtendedRequest getStartTLSRequest()
4612 {
4613 return startTLSRequest;
4614 }
4615
4616
4617
4618 /**
4619 * Retrieves an instance of the {@code LDAPConnectionInternals} object for
4620 * this connection.
4621 *
4622 * @param throwIfDisconnected Indicates whether to throw an
4623 * {@code LDAPException} if the connection is not
4624 * established.
4625 *
4626 * @return The {@code LDAPConnectionInternals} object for this connection, or
4627 * {@code null} if the connection is not established and no exception
4628 * should be thrown.
4629 *
4630 * @throws LDAPException If the connection is not established and
4631 * {@code throwIfDisconnected} is {@code true}.
4632 */
4633 LDAPConnectionInternals getConnectionInternals(
4634 final boolean throwIfDisconnected)
4635 throws LDAPException
4636 {
4637 final LDAPConnectionInternals internals = connectionInternals;
4638 if ((internals == null) && throwIfDisconnected)
4639 {
4640 throw new LDAPException(ResultCode.SERVER_DOWN,
4641 ERR_CONN_NOT_ESTABLISHED.get());
4642 }
4643 else
4644 {
4645 return internals;
4646 }
4647 }
4648
4649
4650
4651 /**
4652 * Retrieves the cached schema for this connection, if applicable.
4653 *
4654 * @return The cached schema for this connection, or {@code null} if it is
4655 * not available (e.g., because the connection is not established,
4656 * because {@link LDAPConnectionOptions#useSchema()} is false, or
4657 * because an error occurred when trying to read the server schema).
4658 */
4659 Schema getCachedSchema()
4660 {
4661 return cachedSchema;
4662 }
4663
4664
4665
4666 /**
4667 * Sets the cached schema for this connection.
4668 *
4669 * @param cachedSchema The cached schema for this connection. It may be
4670 * {@code null} if no cached schema is available.
4671 */
4672 void setCachedSchema(final Schema cachedSchema)
4673 {
4674 this.cachedSchema = cachedSchema;
4675 }
4676
4677
4678
4679 /**
4680 * Indicates whether this connection is operating in synchronous mode.
4681 *
4682 * @return {@code true} if this connection is operating in synchronous mode,
4683 * or {@code false} if not.
4684 */
4685 public boolean synchronousMode()
4686 {
4687 final LDAPConnectionInternals internals = connectionInternals;
4688 if (internals == null)
4689 {
4690 return false;
4691 }
4692 else
4693 {
4694 return internals.synchronousMode();
4695 }
4696 }
4697
4698
4699
4700 /**
4701 * Reads a response from the server, blocking if necessary until the response
4702 * has been received. This should only be used for connections operating in
4703 * synchronous mode.
4704 *
4705 * @param messageID The message ID for the response to be read. Any
4706 * response read with a different message ID will be
4707 * discarded, unless it is an unsolicited notification in
4708 * which case it will be provided to any registered
4709 * unsolicited notification handler.
4710 *
4711 * @return The response read from the server.
4712 *
4713 * @throws LDAPException If a problem occurs while reading the response.
4714 */
4715 LDAPResponse readResponse(final int messageID)
4716 throws LDAPException
4717 {
4718 final LDAPConnectionInternals internals = connectionInternals;
4719 if (internals != null)
4720 {
4721 final LDAPResponse response =
4722 internals.getConnectionReader().readResponse(messageID);
4723 debugLDAPResult(response, this);
4724 return response;
4725 }
4726 else
4727 {
4728 final DisconnectInfo di = disconnectInfo.get();
4729 if (di == null)
4730 {
4731 return new ConnectionClosedResponse(ResultCode.CONNECT_ERROR,
4732 ERR_CONN_READ_RESPONSE_NOT_ESTABLISHED.get());
4733 }
4734 else
4735 {
4736 return new ConnectionClosedResponse(di.getType().getResultCode(),
4737 di.getMessage());
4738 }
4739 }
4740 }
4741
4742
4743
4744 /**
4745 * Retrieves the time that this connection was established in the number of
4746 * milliseconds since January 1, 1970 UTC (the same format used by
4747 * {@code System.currentTimeMillis}.
4748 *
4749 * @return The time that this connection was established, or -1 if the
4750 * connection is not currently established.
4751 */
4752 public long getConnectTime()
4753 {
4754 final LDAPConnectionInternals internals = connectionInternals;
4755 if (internals != null)
4756 {
4757 return internals.getConnectTime();
4758 }
4759 else
4760 {
4761 return -1L;
4762 }
4763 }
4764
4765
4766
4767 /**
4768 * Retrieves the time that this connection was last used to send or receive an
4769 * LDAP message. The value will represent the number of milliseconds since
4770 * January 1, 1970 UTC (the same format used by
4771 * {@code System.currentTimeMillis}.
4772 *
4773 * @return The time that this connection was last used to send or receive an
4774 * LDAP message. If the connection is not established, then -1 will
4775 * be returned. If the connection is established but no
4776 * communication has been performed over the connection since it was
4777 * established, then the value of {@link #getConnectTime()} will be
4778 * returned.
4779 */
4780 public long getLastCommunicationTime()
4781 {
4782 if (lastCommunicationTime > 0L)
4783 {
4784 return lastCommunicationTime;
4785 }
4786 else
4787 {
4788 return getConnectTime();
4789 }
4790 }
4791
4792
4793
4794 /**
4795 * Updates the last communication time for this connection to be the current
4796 * time.
4797 */
4798 void setLastCommunicationTime()
4799 {
4800 lastCommunicationTime = System.currentTimeMillis();
4801 }
4802
4803
4804
4805 /**
4806 * Retrieves the connection statistics for this LDAP connection.
4807 *
4808 * @return The connection statistics for this LDAP connection.
4809 */
4810 public LDAPConnectionStatistics getConnectionStatistics()
4811 {
4812 return connectionStatistics;
4813 }
4814
4815
4816
4817 /**
4818 * Retrieves the number of outstanding operations on this LDAP connection
4819 * (i.e., the number of operations currently in progress). The value will
4820 * only be valid for connections not configured to use synchronous mode.
4821 *
4822 * @return The number of outstanding operations on this LDAP connection, or
4823 * -1 if it cannot be determined (e.g., because the connection is not
4824 * established or is operating in synchronous mode).
4825 */
4826 public int getActiveOperationCount()
4827 {
4828 final LDAPConnectionInternals internals = connectionInternals;
4829
4830 if (internals == null)
4831 {
4832 return -1;
4833 }
4834 else
4835 {
4836 if (internals.synchronousMode())
4837 {
4838 return -1;
4839 }
4840 else
4841 {
4842 return internals.getConnectionReader().getActiveOperationCount();
4843 }
4844 }
4845 }
4846
4847
4848
4849 /**
4850 * Retrieves the schema from the provided connection. If the retrieved schema
4851 * matches schema that's already in use by other connections, the common
4852 * schema will be used instead of the newly-retrieved version.
4853 *
4854 * @param c The connection for which to retrieve the schema.
4855 *
4856 * @return The schema retrieved from the given connection, or a cached
4857 * schema if it matched a schema that was already in use.
4858 *
4859 * @throws LDAPException If a problem is encountered while retrieving or
4860 * parsing the schema.
4861 */
4862 private static Schema getCachedSchema(final LDAPConnection c)
4863 throws LDAPException
4864 {
4865 final Schema s = c.getSchema();
4866
4867 synchronized (SCHEMA_SET)
4868 {
4869 return SCHEMA_SET.addAndGet(s);
4870 }
4871 }
4872
4873
4874
4875 /**
4876 * Retrieves the connection attachment with the specified name.
4877 *
4878 * @param name The name of the attachment to retrieve. It must not be
4879 * {@code null}.
4880 *
4881 * @return The connection attachment with the specified name, or {@code null}
4882 * if there is no such attachment.
4883 */
4884 synchronized Object getAttachment(final String name)
4885 {
4886 if (attachments == null)
4887 {
4888 return null;
4889 }
4890 else
4891 {
4892 return attachments.get(name);
4893 }
4894 }
4895
4896
4897
4898 /**
4899 * Sets a connection attachment with the specified name and value.
4900 *
4901 * @param name The name of the attachment to set. It must not be
4902 * {@code null}.
4903 * @param value The value to use for the attachment. It may be {@code null}
4904 * if an attachment with the specified name should be cleared
4905 * rather than overwritten.
4906 */
4907 synchronized void setAttachment(final String name, final Object value)
4908 {
4909 if (attachments == null)
4910 {
4911 attachments = new HashMap<String,Object>(10);
4912 }
4913
4914 if (value == null)
4915 {
4916 attachments.remove(name);
4917 }
4918 else
4919 {
4920 attachments.put(name, value);
4921 }
4922 }
4923
4924
4925
4926 /**
4927 * Performs any necessary cleanup to ensure that this connection is properly
4928 * closed before it is garbage collected.
4929 *
4930 * @throws Throwable If the superclass finalizer throws an exception.
4931 */
4932 @Override()
4933 protected void finalize()
4934 throws Throwable
4935 {
4936 super.finalize();
4937
4938 setDisconnectInfo(DisconnectType.CLOSED_BY_FINALIZER, null, null);
4939 setClosed();
4940 }
4941
4942
4943
4944 /**
4945 * Retrieves a string representation of this LDAP connection.
4946 *
4947 * @return A string representation of this LDAP connection.
4948 */
4949 @Override()
4950 public String toString()
4951 {
4952 final StringBuilder buffer = new StringBuilder();
4953 toString(buffer);
4954 return buffer.toString();
4955 }
4956
4957
4958
4959 /**
4960 * Appends a string representation of this LDAP connection to the provided
4961 * buffer.
4962 *
4963 * @param buffer The buffer to which to append a string representation of
4964 * this LDAP connection.
4965 */
4966 public void toString(final StringBuilder buffer)
4967 {
4968 buffer.append("LDAPConnection(");
4969
4970 final String name = connectionName;
4971 final String poolName = connectionPoolName;
4972 if (name != null)
4973 {
4974 buffer.append("name='");
4975 buffer.append(name);
4976 buffer.append("', ");
4977 }
4978 else if (poolName != null)
4979 {
4980 buffer.append("poolName='");
4981 buffer.append(poolName);
4982 buffer.append("', ");
4983 }
4984
4985 final LDAPConnectionInternals internals = connectionInternals;
4986 if ((internals != null) && internals.isConnected())
4987 {
4988 buffer.append("connected to ");
4989 buffer.append(internals.getHost());
4990 buffer.append(':');
4991 buffer.append(internals.getPort());
4992 }
4993 else
4994 {
4995 buffer.append("not connected");
4996 }
4997
4998 buffer.append(')');
4999 }
5000 }