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