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