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