001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2009-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2014 ForgeRock AS
026 */
027
028package org.forgerock.opendj.ldap;
029
030import java.io.Closeable;
031import java.util.Collection;
032
033import org.forgerock.i18n.LocalizedIllegalArgumentException;
034import org.forgerock.opendj.ldap.requests.AbandonRequest;
035import org.forgerock.opendj.ldap.requests.AddRequest;
036import org.forgerock.opendj.ldap.requests.BindRequest;
037import org.forgerock.opendj.ldap.requests.CompareRequest;
038import org.forgerock.opendj.ldap.requests.DeleteRequest;
039import org.forgerock.opendj.ldap.requests.ExtendedRequest;
040import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
041import org.forgerock.opendj.ldap.requests.ModifyRequest;
042import org.forgerock.opendj.ldap.requests.SearchRequest;
043import org.forgerock.opendj.ldap.requests.UnbindRequest;
044import org.forgerock.opendj.ldap.responses.BindResult;
045import org.forgerock.opendj.ldap.responses.CompareResult;
046import org.forgerock.opendj.ldap.responses.ExtendedResult;
047import org.forgerock.opendj.ldap.responses.GenericExtendedResult;
048import org.forgerock.opendj.ldap.responses.Result;
049import org.forgerock.opendj.ldap.responses.SearchResultEntry;
050import org.forgerock.opendj.ldap.responses.SearchResultReference;
051import org.forgerock.opendj.ldif.ChangeRecord;
052import org.forgerock.opendj.ldif.ConnectionEntryReader;
053
054/**
055 * A connection with a Directory Server over which read and update operations
056 * may be performed. See RFC 4511 for the LDAPv3 protocol specification and more
057 * information about the types of operations defined in LDAP.
058 * <p>
059 * <h3>Operation processing</h3>
060 * <p>
061 * Operations may be performed synchronously or asynchronously depending on the
062 * method chosen. Asynchronous methods can be identified by their {@code Async}
063 * suffix.
064 * <p>
065 * <h4>Performing operations synchronously</h4>
066 * <p>
067 * Synchronous methods block until a response is received from the Directory
068 * Server, at which point an appropriate {@link Result} object is returned if
069 * the operation succeeded, or thrown as an {@link LdapException} if the
070 * operation failed.
071 * <p>
072 * Since synchronous operations block the calling thread, the only way to
073 * abandon a long running operation is to interrupt the calling thread from
074 * another thread. This will cause the calling thread unblock and throw a
075 * {@link CancelledResultException} whose cause is the underlying
076 * {@link InterruptedException}.
077 * <p>
078 * <h4>Performing operations asynchronously</h4>
079 * <p>
080 * Asynchronous methods, identified by their {@code Async} suffix, are
081 * non-blocking, returning a {@link LdapPromise} or sub-type thereof which can
082 * be used for retrieving the result using the {@link LdapPromise#get} method.
083 * Operation failures, for whatever reason, are signaled by the
084 * {@link LdapPromise#get()} method throwing an {@link LdapException}.
085 * <p>
086 * In addition to returning a {@link LdapPromise}, all asynchronous methods
087 * accept a {@link LdapResultHandler} which will be notified upon completion of the
088 * operation.
089 * <p>
090 * Synchronous operations are easily simulated by immediately getting the
091 * result:
092 *
093 * <pre>
094 * Connection connection = ...;
095 * AddRequest request = ...;
096 * // Will block until operation completes, and
097 * // throws exception on failure.
098 * connection.add(request).get();
099 * </pre>
100 *
101 * Operations can be performed in parallel while taking advantage of the
102 * simplicity of a synchronous application design:
103 *
104 * <pre>
105 * Connection connection1 = ...;
106 * Connection connection2 = ...;
107 * AddRequest request = ...;
108 * // Add the entry to the first server (don't block).
109 * LdapPromise promise1 = connection1.add(request);
110 * // Add the entry to the second server (in parallel).
111 * LdapPromise promise2 = connection2.add(request);
112 * // Total time = is O(1) instead of O(n).
113 * promise1.get();
114 * promise2.get();
115 * </pre>
116 *
117 * More complex client applications can take advantage of a fully asynchronous
118 * event driven design using {@link LdapResultHandler}s:
119 *
120 * <pre>
121 * Connection connection = ...;
122 * SearchRequest request = ...;
123 * // Process results in the search result handler
124 * // in a separate thread.
125 * SearchResponseHandler handle = ...;
126 * connection.search(request, handler);
127 * </pre>
128 * <p>
129 * <h3>Closing connections</h3>
130 * <p>
131 * Applications must ensure that a connection is closed by calling
132 * {@link #close()} even if a fatal error occurs on the connection. Once a
133 * connection has been closed by the client application, any attempts to
134 * continue to use the connection will result in an
135 * {@link IllegalStateException} being thrown. Note that, if a fatal error is
136 * encountered on the connection, then the application can continue to use the
137 * connection. In this case all requests subsequent to the failure will fail
138 * with an appropriate {@link LdapException} when their result is
139 * retrieved.
140 * <p>
141 * <h3>Event notification</h3>
142 * <p>
143 * Applications can choose to be notified when a connection is closed by the
144 * application, receives an unsolicited notification, or experiences a fatal
145 * error by registering a {@link ConnectionEventListener} with the connection
146 * using the {@link #addConnectionEventListener} method.
147 *
148 * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 - Lightweight
149 *      Directory Access Protocol (LDAP): The Protocol </a>
150 */
151public interface Connection extends Closeable {
152
153    /**
154     * Abandons the unfinished operation identified in the provided abandon
155     * request.
156     * <p>
157     * Abandon requests do not have a response, so invoking the method get() on
158     * the returned promise will not block, nor return anything (it is Void), but
159     * may throw an exception if a problem occurred while sending the abandon
160     * request. In addition the returned promise may be used in order to
161     * determine the message ID of the abandon request.
162     * <p>
163     * <b>Note:</b> a more convenient approach to abandoning unfinished
164     * asynchronous operations is provided via the
165     * {@link LdapPromise#cancel(boolean)} method.
166     *
167     * @param request
168     *            The request identifying the operation to be abandoned.
169     * @return A promise whose result is Void.
170     * @throws UnsupportedOperationException
171     *             If this connection does not support abandon operations.
172     * @throws IllegalStateException
173     *             If this connection has already been closed, i.e. if
174     *             {@code isClosed() == true}.
175     * @throws NullPointerException
176     *             If {@code request} was {@code null}.
177     */
178    LdapPromise<Void> abandonAsync(AbandonRequest request);
179
180    /**
181     * Adds an entry to the Directory Server using the provided add request.
182     *
183     * @param request
184     *            The add request.
185     * @return The result of the operation.
186     * @throws LdapException
187     *             If the result code indicates that the request failed for some
188     *             reason.
189     * @throws UnsupportedOperationException
190     *             If this connection does not support add operations.
191     * @throws IllegalStateException
192     *             If this connection has already been closed, i.e. if
193     *             {@code isClosed() == true}.
194     * @throws NullPointerException
195     *             If {@code request} was {@code null}.
196     */
197    Result add(AddRequest request) throws LdapException;
198
199    /**
200     * Adds the provided entry to the Directory Server.
201     * <p>
202     * This method is equivalent to the following code:
203     *
204     * <pre>
205     * AddRequest request = new AddRequest(entry);
206     * connection.add(request);
207     * </pre>
208     *
209     * @param entry
210     *            The entry to be added.
211     * @return The result of the operation.
212     * @throws LdapException
213     *             If the result code indicates that the request failed for some
214     *             reason.
215     * @throws UnsupportedOperationException
216     *             If this connection does not support add operations.
217     * @throws IllegalStateException
218     *             If this connection has already been closed, i.e. if
219     *             {@code isClosed() == true}.
220     * @throws NullPointerException
221     *             If {@code entry} was {@code null} .
222     */
223    Result add(Entry entry) throws LdapException;
224
225    /**
226     * Adds an entry to the Directory Server using the provided lines of LDIF.
227     * <p>
228     * This method is equivalent to the following code:
229     *
230     * <pre>
231     * AddRequest request = new AddRequest(ldifLines);
232     * connection.add(request);
233     * </pre>
234     *
235     * @param ldifLines
236     *            Lines of LDIF containing the an LDIF add change record or an
237     *            LDIF entry record.
238     * @return The result of the operation.
239     * @throws LdapException
240     *             If the result code indicates that the request failed for some
241     *             reason.
242     * @throws UnsupportedOperationException
243     *             If this connection does not support add operations.
244     * @throws LocalizedIllegalArgumentException
245     *             If {@code ldifLines} was empty, or contained invalid LDIF, or
246     *             could not be decoded using the default schema.
247     * @throws IllegalStateException
248     *             If this connection has already been closed, i.e. if
249     *             {@code isClosed() == true}.
250     * @throws NullPointerException
251     *             If {@code ldifLines} was {@code null} .
252     */
253    Result add(String... ldifLines) throws LdapException;
254
255    /**
256     * Asynchronously adds an entry to the Directory Server using the provided
257     * add request.
258     *
259     * @param request
260     *            The add request.
261     * @return A promise representing the result of the operation.
262     * @throws UnsupportedOperationException
263     *             If this connection does not support add operations.
264     * @throws IllegalStateException
265     *             If this connection has already been closed, i.e. if
266     *             {@code isClosed() == true}.
267     * @throws NullPointerException
268     *             If {@code request} was {@code null}.
269     */
270    LdapPromise<Result> addAsync(AddRequest request);
271
272    /**
273     * Asynchronously adds an entry to the Directory Server using the provided
274     * add request.
275     *
276     * @param request
277     *            The add request.
278     * @param intermediateResponseHandler
279     *            An intermediate response handler which can be used to process
280     *            any intermediate responses as they are received, may be
281     *            {@code null}.
282     * @return A promise representing the result of the operation.
283     * @throws UnsupportedOperationException
284     *             If this connection does not support add operations.
285     * @throws IllegalStateException
286     *             If this connection has already been closed, i.e. if
287     *             {@code isClosed() == true}.
288     * @throws NullPointerException
289     *             If {@code request} was {@code null}.
290     */
291    LdapPromise<Result> addAsync(AddRequest request, IntermediateResponseHandler intermediateResponseHandler);
292
293    /**
294     * Registers the provided connection event listener so that it will be
295     * notified when this connection is closed by the application, receives an
296     * unsolicited notification, or experiences a fatal error.
297     *
298     * @param listener
299     *            The listener which wants to be notified when events occur on
300     *            this connection.
301     * @throws IllegalStateException
302     *             If this connection has already been closed, i.e. if
303     *             {@code isClosed() == true}.
304     * @throws NullPointerException
305     *             If the {@code listener} was {@code null}.
306     */
307    void addConnectionEventListener(ConnectionEventListener listener);
308
309    /**
310     * Applies the provided change request to the Directory Server.
311     *
312     * @param request
313     *            The change request.
314     * @return The result of the operation.
315     * @throws LdapException
316     *             If the result code indicates that the request failed for some
317     *             reason.
318     * @throws UnsupportedOperationException
319     *             If this connection does not support the provided change
320     *             request.
321     * @throws IllegalStateException
322     *             If this connection has already been closed, i.e. if
323     *             {@code isClosed() == true}.
324     * @throws NullPointerException
325     *             If {@code request} was {@code null}.
326     */
327    Result applyChange(ChangeRecord request) throws LdapException;
328
329    /**
330     * Asynchronously applies the provided change request to the Directory
331     * Server.
332     *
333     * @param request
334     *            The change request.
335     * @return A promise representing the result of the operation.
336     * @throws UnsupportedOperationException
337     *             If this connection does not support the provided change
338     *             request.
339     * @throws IllegalStateException
340     *             If this connection has already been closed, i.e. if
341     *             {@code isClosed() == true}.
342     * @throws NullPointerException
343     *             If {@code request} was {@code null}.
344     */
345    LdapPromise<Result> applyChangeAsync(ChangeRecord request);
346
347    /**
348     * Asynchronously applies the provided change request to the Directory
349     * Server.
350     *
351     * @param request
352     *            The change request.
353     * @param intermediateResponseHandler
354     *            An intermediate response handler which can be used to process
355     *            any intermediate responses as they are received, may be
356     *            {@code null}.
357     * @return A promise representing the result of the operation.
358     * @throws UnsupportedOperationException
359     *             If this connection does not support the provided change
360     *             request.
361     * @throws IllegalStateException
362     *             If this connection has already been closed, i.e. if
363     *             {@code isClosed() == true}.
364     * @throws NullPointerException
365     *             If {@code request} was {@code null}.
366     */
367    LdapPromise<Result> applyChangeAsync(ChangeRecord request,
368        IntermediateResponseHandler intermediateResponseHandler);
369
370    /**
371     * Authenticates to the Directory Server using the provided bind request.
372     *
373     * @param request
374     *            The bind request.
375     * @return The result of the operation.
376     * @throws LdapException
377     *             If the result code indicates that the request failed for some
378     *             reason.
379     * @throws UnsupportedOperationException
380     *             If this connection does not support bind operations.
381     * @throws IllegalStateException
382     *             If this connection has already been closed, i.e. if
383     *             {@code isClosed() == true}.
384     * @throws NullPointerException
385     *             If {@code request} was {@code null}.
386     */
387    BindResult bind(BindRequest request) throws LdapException;
388
389    /**
390     * Authenticates to the Directory Server using simple authentication and the
391     * provided user name and password.
392     * <p>
393     * This method is equivalent to the following code:
394     *
395     * <pre>
396     * BindRequest request = new SimpleBindRequest(name, password);
397     * connection.bind(request);
398     * </pre>
399     *
400     * @param name
401     *            The distinguished name of the Directory object that the client
402     *            wishes to bind as, which may be empty.
403     * @param password
404     *            The password of the Directory object that the client wishes to
405     *            bind as, which may be empty.
406     * @return The result of the operation.
407     * @throws LdapException
408     *             If the result code indicates that the request failed for some
409     *             reason.
410     * @throws LocalizedIllegalArgumentException
411     *             If {@code name} could not be decoded using the default
412     *             schema.
413     * @throws UnsupportedOperationException
414     *             If this connection does not support bind operations.
415     * @throws IllegalStateException
416     *             If this connection has already been closed, i.e. if
417     *             {@code isClosed() == true}.
418     * @throws NullPointerException
419     *             If {@code name} or {@code password} was {@code null}.
420     */
421    BindResult bind(String name, char[] password) throws LdapException;
422
423    /**
424     * Asynchronously authenticates to the Directory Server using the provided
425     * bind request.
426     *
427     * @param request
428     *            The bind request.
429     * @return A promise representing the result of the operation.
430     * @throws UnsupportedOperationException
431     *             If this connection does not support bind operations.
432     * @throws IllegalStateException
433     *             If this connection has already been closed, i.e. if
434     *             {@code isClosed() == true}.
435     * @throws NullPointerException
436     *             If {@code request} was {@code null}.
437     */
438    LdapPromise<BindResult> bindAsync(BindRequest request);
439
440    /**
441     * Asynchronously authenticates to the Directory Server using the provided
442     * bind request.
443     *
444     * @param request
445     *            The bind request.
446     * @param intermediateResponseHandler
447     *            An intermediate response handler which can be used to process
448     *            any intermediate responses as they are received, may be
449     *            {@code null}.
450     * @return A promise representing the result of the operation.
451     * @throws UnsupportedOperationException
452     *             If this connection does not support bind operations.
453     * @throws IllegalStateException
454     *             If this connection has already been closed, i.e. if
455     *             {@code isClosed() == true}.
456     * @throws NullPointerException
457     *             If {@code request} was {@code null}.
458     */
459    LdapPromise<BindResult> bindAsync(BindRequest request, IntermediateResponseHandler intermediateResponseHandler);
460
461    /**
462     * Releases any resources associated with this connection. For physical
463     * connections to a Directory Server this will mean that an unbind request
464     * is sent and the underlying socket is closed.
465     * <p>
466     * Other connection implementations may behave differently, and may choose
467     * not to send an unbind request if its use is inappropriate (for example a
468     * pooled connection will be released and returned to its connection pool
469     * without ever issuing an unbind request).
470     * <p>
471     * This method is equivalent to the following code:
472     *
473     * <pre>
474     * UnbindRequest request = new UnbindRequest();
475     * connection.close(request);
476     * </pre>
477     *
478     * Calling {@code close} on a connection that is already closed has no
479     * effect.
480     *
481     * @see Connections#uncloseable(Connection)
482     */
483    @Override
484    void close();
485
486    /**
487     * Releases any resources associated with this connection. For physical
488     * connections to a Directory Server this will mean that the provided unbind
489     * request is sent and the underlying socket is closed.
490     * <p>
491     * Other connection implementations may behave differently, and may choose
492     * to ignore the provided unbind request if its use is inappropriate (for
493     * example a pooled connection will be released and returned to its
494     * connection pool without ever issuing an unbind request).
495     * <p>
496     * Calling {@code close} on a connection that is already closed has no
497     * effect.
498     *
499     * @param request
500     *            The unbind request to use in the case where a physical
501     *            connection is closed.
502     * @param reason
503     *            A reason describing why the connection was closed.
504     * @throws NullPointerException
505     *             If {@code request} was {@code null}.
506     */
507    void close(UnbindRequest request, String reason);
508
509    /**
510     * Compares an entry in the Directory Server using the provided compare
511     * request.
512     *
513     * @param request
514     *            The compare request.
515     * @return The result of the operation.
516     * @throws LdapException
517     *             If the result code indicates that the request failed for some
518     *             reason.
519     * @throws UnsupportedOperationException
520     *             If this connection does not support compare operations.
521     * @throws IllegalStateException
522     *             If this connection has already been closed, i.e. if
523     *             {@code isClosed() == true}.
524     * @throws NullPointerException
525     *             If {@code request} was {@code null}.
526     */
527    CompareResult compare(CompareRequest request) throws LdapException;
528
529    /**
530     * Compares the named entry in the Directory Server against the provided
531     * attribute value assertion.
532     * <p>
533     * This method is equivalent to the following code:
534     *
535     * <pre>
536     * CompareRequest request = new CompareRequest(name, attributeDescription, assertionValue);
537     * connection.compare(request);
538     * </pre>
539     *
540     * @param name
541     *            The distinguished name of the entry to be compared.
542     * @param attributeDescription
543     *            The name of the attribute to be compared.
544     * @param assertionValue
545     *            The assertion value to be compared.
546     * @return The result of the operation.
547     * @throws LdapException
548     *             If the result code indicates that the request failed for some
549     *             reason.
550     * @throws LocalizedIllegalArgumentException
551     *             If {@code name} or {@code AttributeDescription} could not be
552     *             decoded using the default schema.
553     * @throws UnsupportedOperationException
554     *             If this connection does not support compare operations.
555     * @throws IllegalStateException
556     *             If this connection has already been closed, i.e. if
557     *             {@code isClosed() == true}.
558     * @throws NullPointerException
559     *             If {@code name}, {@code attributeDescription}, or
560     *             {@code assertionValue} was {@code null}.
561     */
562    CompareResult compare(String name, String attributeDescription, String assertionValue)
563            throws LdapException;
564
565    /**
566     * Asynchronously compares an entry in the Directory Server using the
567     * provided compare request.
568     *
569     * @param request
570     *            The compare request.
571     * @return A promise representing the result of the operation.
572     * @throws UnsupportedOperationException
573     *             If this connection does not support compare operations.
574     * @throws IllegalStateException
575     *             If this connection has already been closed, i.e. if
576     *             {@code isClosed() == true}.
577     * @throws NullPointerException
578     *             If {@code request} was {@code null}.
579     */
580    LdapPromise<CompareResult> compareAsync(CompareRequest request);
581
582    /**
583     * Asynchronously compares an entry in the Directory Server using the
584     * provided compare request.
585     *
586     * @param request
587     *            The compare request.
588     * @param intermediateResponseHandler
589     *            An intermediate response handler which can be used to process
590     *            any intermediate responses as they are received, may be
591     *            {@code null}.
592     * @return A promise representing the result of the operation.
593     * @throws UnsupportedOperationException
594     *             If this connection does not support compare operations.
595     * @throws IllegalStateException
596     *             If this connection has already been closed, i.e. if
597     *             {@code isClosed() == true}.
598     * @throws NullPointerException
599     *             If {@code request} was {@code null}.
600     */
601    LdapPromise<CompareResult> compareAsync(CompareRequest request,
602        IntermediateResponseHandler intermediateResponseHandler);
603
604    /**
605     * Deletes an entry from the Directory Server using the provided delete
606     * request.
607     *
608     * @param request
609     *            The delete request.
610     * @return The result of the operation.
611     * @throws LdapException
612     *             If the result code indicates that the request failed for some
613     *             reason.
614     * @throws UnsupportedOperationException
615     *             If this connection does not support delete operations.
616     * @throws IllegalStateException
617     *             If this connection has already been closed, i.e. if
618     *             {@code isClosed() == true}.
619     * @throws NullPointerException
620     *             If {@code request} was {@code null}.
621     */
622    Result delete(DeleteRequest request) throws LdapException;
623
624    /**
625     * Deletes the named entry from the Directory Server.
626     * <p>
627     * This method is equivalent to the following code:
628     *
629     * <pre>
630     * DeleteRequest request = new DeleteRequest(name);
631     * connection.delete(request);
632     * </pre>
633     *
634     * @param name
635     *            The distinguished name of the entry to be deleted.
636     * @return The result of the operation.
637     * @throws LdapException
638     *             If the result code indicates that the request failed for some
639     *             reason.
640     * @throws LocalizedIllegalArgumentException
641     *             If {@code name} could not be decoded using the default
642     *             schema.
643     * @throws UnsupportedOperationException
644     *             If this connection does not support delete operations.
645     * @throws IllegalStateException
646     *             If this connection has already been closed, i.e. if
647     *             {@code isClosed() == true}.
648     * @throws NullPointerException
649     *             If {@code name} was {@code null}.
650     */
651    Result delete(String name) throws LdapException;
652
653    /**
654     * Deletes the named entry and all of its subordinates from the Directory
655     * Server.
656     * <p>
657     * This method is equivalent to the following code:
658     *
659     * <pre>
660     * DeleteRequest request = new DeleteRequest(name).addControl(
661     * connection.delete(request);
662     * </pre>
663     *
664     * @param name
665     *            The distinguished name of the subtree base entry to be
666     *            deleted.
667     * @return The result of the operation.
668     * @throws LdapException
669     *             If the result code indicates that the request failed for some
670     *             reason.
671     * @throws LocalizedIllegalArgumentException
672     *             If {@code name} could not be decoded using the default
673     *             schema.
674     * @throws UnsupportedOperationException
675     *             If this connection does not support delete operations.
676     * @throws IllegalStateException
677     *             If this connection has already been closed, i.e. if
678     *             {@code isClosed() == true}.
679     * @throws NullPointerException
680     *             If {@code name} was {@code null}.
681     */
682    Result deleteSubtree(String name) throws LdapException;
683
684    /**
685     * Asynchronously deletes an entry from the Directory Server using the
686     * provided delete request.
687     *
688     * @param request
689     *            The delete request.
690     * @return A promise representing the result of the operation.
691     * @throws UnsupportedOperationException
692     *             If this connection does not support delete operations.
693     * @throws IllegalStateException
694     *             If this connection has already been closed, i.e. if
695     *             {@code isClosed() == true}.
696     * @throws NullPointerException
697     *             If {@code request} was {@code null}.
698     */
699    LdapPromise<Result> deleteAsync(DeleteRequest request);
700
701    /**
702     * Asynchronously deletes an entry from the Directory Server using the
703     * provided delete request.
704     *
705     * @param request
706     *            The delete request.
707     * @param intermediateResponseHandler
708     *            An intermediate response handler which can be used to process
709     *            any intermediate responses as they are received, may be
710     *            {@code null}.
711     * @return A promise representing the result of the operation.
712     * @throws UnsupportedOperationException
713     *             If this connection does not support delete operations.
714     * @throws IllegalStateException
715     *             If this connection has already been closed, i.e. if
716     *             {@code isClosed() == true}.
717     * @throws NullPointerException
718     *             If {@code request} was {@code null}.
719     */
720    LdapPromise<Result> deleteAsync(DeleteRequest request, IntermediateResponseHandler intermediateResponseHandler);
721
722    /**
723     * Requests that the Directory Server performs the provided extended
724     * request.
725     *
726     * @param <R>
727     *            The type of result returned by the extended request.
728     * @param request
729     *            The extended request.
730     * @return The result of the operation.
731     * @throws LdapException
732     *             If the result code indicates that the request failed for some
733     *             reason.
734     * @throws UnsupportedOperationException
735     *             If this connection does not support extended operations.
736     * @throws IllegalStateException
737     *             If this connection has already been closed, i.e. if
738     *             {@code isClosed() == true}.
739     * @throws NullPointerException
740     *             If {@code request} was {@code null}.
741     */
742    <R extends ExtendedResult> R extendedRequest(ExtendedRequest<R> request) throws LdapException;
743
744    /**
745     * Requests that the Directory Server performs the provided extended
746     * request, optionally listening for any intermediate responses.
747     *
748     * @param <R>
749     *            The type of result returned by the extended request.
750     * @param request
751     *            The extended request.
752     * @param handler
753     *            An intermediate response handler which can be used to process
754     *            any intermediate responses as they are received, may be
755     *            {@code null}.
756     * @return The result of the operation.
757     * @throws LdapException
758     *             If the result code indicates that the request failed for some
759     *             reason.
760     * @throws UnsupportedOperationException
761     *             If this connection does not support extended operations.
762     * @throws IllegalStateException
763     *             If this connection has already been closed, i.e. if
764     *             {@code isClosed() == true}.
765     * @throws NullPointerException
766     *             If {@code request} was {@code null}.
767     */
768    <R extends ExtendedResult> R extendedRequest(ExtendedRequest<R> request, IntermediateResponseHandler handler)
769            throws LdapException;
770
771    /**
772     * Requests that the Directory Server performs the provided extended
773     * request.
774     * <p>
775     * This method is equivalent to the following code:
776     *
777     * <pre>
778     * GenericExtendedRequest request = new GenericExtendedRequest(requestName, requestValue);
779     * connection.extendedRequest(request);
780     * </pre>
781     *
782     * @param requestName
783     *            The dotted-decimal representation of the unique OID
784     *            corresponding to the extended request.
785     * @param requestValue
786     *            The content of the extended request in a form defined by the
787     *            extended operation, or {@code null} if there is no content.
788     * @return The result of the operation.
789     * @throws LdapException
790     *             If the result code indicates that the request failed for some
791     *             reason.
792     * @throws UnsupportedOperationException
793     *             If this connection does not support extended operations.
794     * @throws IllegalStateException
795     *             If this connection has already been closed, i.e. if
796     *             {@code isClosed() == true}.
797     * @throws NullPointerException
798     *             If {@code requestName} was {@code null}.
799     */
800    GenericExtendedResult extendedRequest(String requestName, ByteString requestValue) throws LdapException;
801
802    /**
803     * Asynchronously performs the provided extended request in the Directory
804     * Server.
805     *
806     * @param <R>
807     *            The type of result returned by the extended request.
808     * @param request
809     *            The extended request.
810     * @return A promise representing the result of the operation.
811     * @throws UnsupportedOperationException
812     *             If this connection does not support extended operations.
813     * @throws IllegalStateException
814     *             If this connection has already been closed, i.e. if
815     *             {@code isClosed() == true}.
816     * @throws NullPointerException
817     *             If {@code request} was {@code null}.
818     */
819    <R extends ExtendedResult> LdapPromise<R> extendedRequestAsync(ExtendedRequest<R> request);
820
821    /**
822     * Asynchronously performs the provided extended request in the Directory
823     * Server.
824     *
825     * @param <R>
826     *            The type of result returned by the extended request.
827     * @param request
828     *            The extended request.
829     * @param intermediateResponseHandler
830     *            An intermediate response handler which can be used to process
831     *            any intermediate responses as they are received, may be
832     *            {@code null}.
833     * @return A promise representing the result of the operation.
834     * @throws UnsupportedOperationException
835     *             If this connection does not support extended operations.
836     * @throws IllegalStateException
837     *             If this connection has already been closed, i.e. if
838     *             {@code isClosed() == true}.
839     * @throws NullPointerException
840     *             If {@code request} was {@code null}.
841     */
842    <R extends ExtendedResult> LdapPromise<R> extendedRequestAsync(ExtendedRequest<R> request,
843        IntermediateResponseHandler intermediateResponseHandler);
844
845    /**
846     * Indicates whether or not this connection has been explicitly closed by
847     * calling {@code close}. This method will not return {@code true} if a
848     * fatal error has occurred on the connection unless {@code close} has been
849     * called.
850     *
851     * @return {@code true} if this connection has been explicitly closed by
852     *         calling {@code close}, or {@code false} otherwise.
853     */
854    boolean isClosed();
855
856    /**
857     * Returns {@code true} if this connection has not been closed and no fatal
858     * errors have been detected. This method is guaranteed to return
859     * {@code false} only when it is called after the method {@code close} has
860     * been called.
861     *
862     * @return {@code true} if this connection is valid, {@code false}
863     *         otherwise.
864     */
865    boolean isValid();
866
867    /**
868     * Modifies an entry in the Directory Server using the provided modify
869     * request.
870     *
871     * @param request
872     *            The modify request.
873     * @return The result of the operation.
874     * @throws LdapException
875     *             If the result code indicates that the request failed for some
876     *             reason.
877     * @throws UnsupportedOperationException
878     *             If this connection does not support modify operations.
879     * @throws IllegalStateException
880     *             If this connection has already been closed, i.e. if
881     *             {@code isClosed() == true}.
882     * @throws NullPointerException
883     *             If {@code request} was {@code null}.
884     */
885    Result modify(ModifyRequest request) throws LdapException;
886
887    /**
888     * Modifies an entry in the Directory Server using the provided lines of
889     * LDIF.
890     * <p>
891     * This method is equivalent to the following code:
892     *
893     * <pre>
894     * ModifyRequest request = new ModifyRequest(name, ldifChanges);
895     * connection.modify(request);
896     * </pre>
897     *
898     * @param ldifLines
899     *            Lines of LDIF containing the a single LDIF modify change
900     *            record.
901     * @return The result of the operation.
902     * @throws LdapException
903     *             If the result code indicates that the request failed for some
904     *             reason.
905     * @throws UnsupportedOperationException
906     *             If this connection does not support modify operations.
907     * @throws LocalizedIllegalArgumentException
908     *             If {@code ldifLines} was empty, or contained invalid LDIF, or
909     *             could not be decoded using the default schema.
910     * @throws IllegalStateException
911     *             If this connection has already been closed, i.e. if
912     *             {@code isClosed() == true}.
913     * @throws NullPointerException
914     *             If {@code ldifLines} was {@code null} .
915     */
916    Result modify(String... ldifLines) throws LdapException;
917
918    /**
919     * Asynchronously modifies an entry in the Directory Server using the
920     * provided modify request.
921     *
922     * @param request
923     *            The modify request.
924     * @return A promise representing the result of the operation.
925     * @throws UnsupportedOperationException
926     *             If this connection does not support modify operations.
927     * @throws IllegalStateException
928     *             If this connection has already been closed, i.e. if
929     *             {@code isClosed() == true}.
930     * @throws NullPointerException
931     *             If {@code request} was {@code null}.
932     */
933    LdapPromise<Result> modifyAsync(ModifyRequest request);
934
935    /**
936     * Asynchronously modifies an entry in the Directory Server using the
937     * provided modify request.
938     *
939     * @param request
940     *            The modify request.
941     * @param intermediateResponseHandler
942     *            An intermediate response handler which can be used to process
943     *            any intermediate responses as they are received, may be
944     *            {@code null}.
945     * @return A promise representing the result of the operation.
946     * @throws UnsupportedOperationException
947     *             If this connection does not support modify operations.
948     * @throws IllegalStateException
949     *             If this connection has already been closed, i.e. if
950     *             {@code isClosed() == true}.
951     * @throws NullPointerException
952     *             If {@code request} was {@code null}.
953     */
954    LdapPromise<Result> modifyAsync(ModifyRequest request, IntermediateResponseHandler intermediateResponseHandler);
955
956    /**
957     * Renames an entry in the Directory Server using the provided modify DN
958     * request.
959     *
960     * @param request
961     *            The modify DN request.
962     * @return The result of the operation.
963     * @throws LdapException
964     *             If the result code indicates that the request failed for some
965     *             reason.
966     * @throws UnsupportedOperationException
967     *             If this connection does not support modify DN operations.
968     * @throws IllegalStateException
969     *             If this connection has already been closed, i.e. if
970     *             {@code isClosed() == true}.
971     * @throws NullPointerException
972     *             If {@code request} was {@code null}.
973     */
974    Result modifyDN(ModifyDNRequest request) throws LdapException;
975
976    /**
977     * Renames the named entry in the Directory Server using the provided new
978     * RDN.
979     * <p>
980     * This method is equivalent to the following code:
981     *
982     * <pre>
983     * ModifyDNRequest request = new ModifyDNRequest(name, newRDN);
984     * connection.modifyDN(request);
985     * </pre>
986     *
987     * @param name
988     *            The distinguished name of the entry to be renamed.
989     * @param newRDN
990     *            The new RDN of the entry.
991     * @return The result of the operation.
992     * @throws LdapException
993     *             If the result code indicates that the request failed for some
994     *             reason.
995     * @throws LocalizedIllegalArgumentException
996     *             If {@code name} or {@code newRDN} could not be decoded using
997     *             the default schema.
998     * @throws UnsupportedOperationException
999     *             If this connection does not support modify DN operations.
1000     * @throws IllegalStateException
1001     *             If this connection has already been closed, i.e. if
1002     *             {@code isClosed() == true}.
1003     * @throws NullPointerException
1004     *             If {@code name} or {@code newRDN} was {@code null}.
1005     */
1006    Result modifyDN(String name, String newRDN) throws LdapException;
1007
1008    /**
1009     * Asynchronously renames an entry in the Directory Server using the
1010     * provided modify DN request.
1011     *
1012     * @param request
1013     *            The modify DN request.
1014     * @return A promise representing the result of the operation.
1015     * @throws UnsupportedOperationException
1016     *             If this connection does not support modify DN operations.
1017     * @throws IllegalStateException
1018     *             If this connection has already been closed, i.e. if
1019     *             {@code isClosed() == true}.
1020     * @throws NullPointerException
1021     *             If {@code request} was {@code null}.
1022     */
1023    LdapPromise<Result> modifyDNAsync(ModifyDNRequest request);
1024
1025    /**
1026     * Asynchronously renames an entry in the Directory Server using the
1027     * provided modify DN request.
1028     *
1029     * @param request
1030     *            The modify DN request.
1031     * @param intermediateResponseHandler
1032     *            An intermediate response handler which can be used to process
1033     *            any intermediate responses as they are received, may be
1034     *            {@code null}.
1035     * @return A promise representing the result of the operation.
1036     * @throws UnsupportedOperationException
1037     *             If this connection does not support modify DN operations.
1038     * @throws IllegalStateException
1039     *             If this connection has already been closed, i.e. if
1040     *             {@code isClosed() == true}.
1041     * @throws NullPointerException
1042     *             If {@code request} was {@code null}.
1043     */
1044    LdapPromise<Result> modifyDNAsync(ModifyDNRequest request,
1045        IntermediateResponseHandler intermediateResponseHandler);
1046
1047    /**
1048     * Reads the named entry from the Directory Server.
1049     * <p>
1050     * If the requested entry is not returned by the Directory Server then the
1051     * request will fail with an {@link EntryNotFoundException}. More
1052     * specifically, this method will never return {@code null}.
1053     * <p>
1054     * This method is equivalent to the following code:
1055     *
1056     * <pre>
1057     * SearchRequest request = new SearchRequest(name, SearchScope.BASE_OBJECT,
1058     * &quot;(objectClass=*)&quot;, attributeDescriptions);
1059     * connection.searchSingleEntry(request);
1060     * </pre>
1061     *
1062     * @param name
1063     *            The distinguished name of the entry to be read.
1064     * @param attributeDescriptions
1065     *            The names of the attributes to be included with the entry,
1066     *            which may be {@code null} or empty indicating that all user
1067     *            attributes should be returned.
1068     * @return The single search result entry returned from the search.
1069     * @throws LdapException
1070     *             If the result code indicates that the request failed for some
1071     *             reason.
1072     * @throws UnsupportedOperationException
1073     *             If this connection does not support search operations.
1074     * @throws IllegalStateException
1075     *             If this connection has already been closed, i.e. if
1076     *             {@code isClosed() == true}.
1077     * @throws NullPointerException
1078     *             If the {@code name} was {@code null}.
1079     */
1080    SearchResultEntry readEntry(DN name, String... attributeDescriptions) throws LdapException;
1081
1082    /**
1083     * Reads the named entry from the Directory Server.
1084     * <p>
1085     * If the requested entry is not returned by the Directory Server then the
1086     * request will fail with an {@link EntryNotFoundException}. More
1087     * specifically, this method will never return {@code null}.
1088     * <p>
1089     * This method is equivalent to the following code:
1090     *
1091     * <pre>
1092     * SearchRequest request =
1093     *         new SearchRequest(name, SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
1094     * connection.searchSingleEntry(request);
1095     * </pre>
1096     *
1097     * @param name
1098     *            The distinguished name of the entry to be read.
1099     * @param attributeDescriptions
1100     *            The names of the attributes to be included with the entry.
1101     * @return The single search result entry returned from the search.
1102     * @throws LdapException
1103     *             If the result code indicates that the request failed for some
1104     *             reason.
1105     * @throws LocalizedIllegalArgumentException
1106     *             If {@code baseObject} could not be decoded using the default
1107     *             schema.
1108     * @throws UnsupportedOperationException
1109     *             If this connection does not support search operations.
1110     * @throws IllegalStateException
1111     *             If this connection has already been closed, i.e. if
1112     *             {@code isClosed() == true}.
1113     * @throws NullPointerException
1114     *             If the {@code name} was {@code null}.
1115     */
1116    SearchResultEntry readEntry(String name, String... attributeDescriptions) throws LdapException;
1117
1118    /**
1119     * Asynchronously reads the named entry from the Directory Server.
1120     * <p>
1121     * If the requested entry is not returned by the Directory Server then the
1122     * request will fail with an {@link EntryNotFoundException}. More
1123     * specifically, the returned promise will never return {@code null}.
1124     * <p>
1125     * This method is equivalent to the following code:
1126     *
1127     * <pre>
1128     * SearchRequest request =
1129     *         new SearchRequest(name, SearchScope.BASE_OBJECT, &quot;(objectClass=*)&quot;, attributeDescriptions);
1130     * connection.searchSingleEntryAsync(request, resultHandler, p);
1131     * </pre>
1132     *
1133     * @param name
1134     *            The distinguished name of the entry to be read.
1135     * @param attributeDescriptions
1136     *            The names of the attributes to be included with the entry,
1137     *            which may be {@code null} or empty indicating that all user
1138     *            attributes should be returned.
1139     * @return A promise representing the result of the operation.
1140     * @throws UnsupportedOperationException
1141     *             If this connection does not support search operations.
1142     * @throws IllegalStateException
1143     *             If this connection has already been closed, i.e. if
1144     *             {@code isClosed() == true}.
1145     * @throws NullPointerException
1146     *             If the {@code name} was {@code null}.
1147     */
1148    LdapPromise<SearchResultEntry> readEntryAsync(DN name, Collection<String> attributeDescriptions);
1149
1150    /**
1151     * Removes the provided connection event listener from this connection so
1152     * that it will no longer be notified when this connection is closed by the
1153     * application, receives an unsolicited notification, or experiences a fatal
1154     * error.
1155     *
1156     * @param listener
1157     *            The listener which no longer wants to be notified when events
1158     *            occur on this connection.
1159     * @throws NullPointerException
1160     *             If the {@code listener} was {@code null}.
1161     */
1162    void removeConnectionEventListener(ConnectionEventListener listener);
1163
1164    /**
1165     * Searches the Directory Server using the provided search parameters. Any
1166     * matching entries returned by the search will be exposed through the
1167     * returned {@code ConnectionEntryReader}.
1168     * <p>
1169     * Unless otherwise specified, calling this method is equivalent to:
1170     *
1171     * <pre>
1172     * ConnectionEntryReader reader = new ConnectionEntryReader(this, request);
1173     * </pre>
1174     *
1175     * @param request
1176     *            The search request.
1177     * @return The result of the operation.
1178     * @throws UnsupportedOperationException
1179     *             If this connection does not support search operations.
1180     * @throws IllegalStateException
1181     *             If this connection has already been closed, i.e. if
1182     *             {@code isClosed() == true}.
1183     * @throws NullPointerException
1184     *             If {@code request} or {@code entries} was {@code null}.
1185     */
1186    ConnectionEntryReader search(SearchRequest request);
1187
1188    /**
1189     * Searches the Directory Server using the provided search request. Any
1190     * matching entries returned by the search will be added to {@code entries},
1191     * even if the final search result indicates that the search failed. Search
1192     * result references will be discarded.
1193     * <p>
1194     * <b>Warning:</b> Usage of this method is discouraged if the search request
1195     * is expected to yield a large number of search results since the entire
1196     * set of results will be stored in memory, potentially causing an
1197     * {@code OutOfMemoryError}.
1198     * <p>
1199     * This method is equivalent to the following code:
1200     *
1201     * <pre>
1202     * connection.search(request, entries, null);
1203     * </pre>
1204     *
1205     * @param request
1206     *            The search request.
1207     * @param entries
1208     *            The collection to which matching entries should be added.
1209     * @return The result of the operation.
1210     * @throws LdapException
1211     *             If the result code indicates that the request failed for some
1212     *             reason.
1213     * @throws UnsupportedOperationException
1214     *             If this connection does not support search operations.
1215     * @throws IllegalStateException
1216     *             If this connection has already been closed, i.e. if
1217     *             {@code isClosed() == true}.
1218     * @throws NullPointerException
1219     *             If {@code request} or {@code entries} was {@code null}.
1220     */
1221    Result search(SearchRequest request, Collection<? super SearchResultEntry> entries) throws LdapException;
1222
1223    /**
1224     * Searches the Directory Server using the provided search request. Any
1225     * matching entries returned by the search will be added to {@code entries},
1226     * even if the final search result indicates that the search failed.
1227     * Similarly, search result references returned by the search will be added
1228     * to {@code references}.
1229     * <p>
1230     * <b>Warning:</b> Usage of this method is discouraged if the search request
1231     * is expected to yield a large number of search results since the entire
1232     * set of results will be stored in memory, potentially causing an
1233     * {@code OutOfMemoryError}.
1234     *
1235     * @param request
1236     *            The search request.
1237     * @param entries
1238     *            The collection to which matching entries should be added.
1239     * @param references
1240     *            The collection to which search result references should be
1241     *            added, or {@code null} if references are to be discarded.
1242     * @return The result of the operation.
1243     * @throws LdapException
1244     *             If the result code indicates that the request failed for some
1245     *             reason.
1246     * @throws UnsupportedOperationException
1247     *             If this connection does not support search operations.
1248     * @throws IllegalStateException
1249     *             If this connection has already been closed, i.e. if
1250     *             {@code isClosed() == true}.
1251     * @throws NullPointerException
1252     *             If {@code request} or {@code entries} was {@code null}.
1253     */
1254    Result search(SearchRequest request, Collection<? super SearchResultEntry> entries,
1255            Collection<? super SearchResultReference> references) throws LdapException;
1256
1257    /**
1258     * Searches the Directory Server using the provided search request. Any
1259     * matching entries returned by the search as well as any search result
1260     * references will be passed to the provided search result handler.
1261     *
1262     * @param request
1263     *            The search request.
1264     * @param handler
1265     *            A search result handler which can be used to process the
1266     *            search result entries and references as they are received, may
1267     *            be {@code null}.
1268     * @return The result of the operation.
1269     * @throws LdapException
1270     *             If the result code indicates that the request failed for some
1271     *             reason.
1272     * @throws UnsupportedOperationException
1273     *             If this connection does not support search operations.
1274     * @throws IllegalStateException
1275     *             If this connection has already been closed, i.e. if
1276     *             {@code isClosed() == true}.
1277     * @throws NullPointerException
1278     *             If {@code request} was {@code null}.
1279     */
1280    Result search(SearchRequest request, SearchResultHandler handler) throws LdapException;
1281
1282    /**
1283     * Searches the Directory Server using the provided search parameters. Any
1284     * matching entries returned by the search will be exposed through the
1285     * {@code EntryReader} interface.
1286     * <p>
1287     * <b>Warning:</b> When using a queue with an optional capacity bound, the
1288     * connection will stop reading responses and wait if necessary for space to
1289     * become available.
1290     * <p>
1291     * This method is equivalent to the following code:
1292     *
1293     * <pre>
1294     * SearchRequest request = new SearchRequest(baseDN, scope, filter, attributeDescriptions);
1295     * connection.search(request, new LinkedBlockingQueue&lt;Response&gt;());
1296     * </pre>
1297     *
1298     * @param baseObject
1299     *            The distinguished name of the base entry relative to which the
1300     *            search is to be performed.
1301     * @param scope
1302     *            The scope of the search.
1303     * @param filter
1304     *            The filter that defines the conditions that must be fulfilled
1305     *            in order for an entry to be returned.
1306     * @param attributeDescriptions
1307     *            The names of the attributes to be included with each entry.
1308     * @return An entry reader exposing the returned entries.
1309     * @throws UnsupportedOperationException
1310     *             If this connection does not support search operations.
1311     * @throws IllegalStateException
1312     *             If this connection has already been closed, i.e. if
1313     *             {@code isClosed() == true}.
1314     * @throws NullPointerException
1315     *             If the {@code baseObject}, {@code scope}, or {@code filter}
1316     *             were {@code null}.
1317     */
1318    ConnectionEntryReader search(String baseObject, SearchScope scope, String filter,
1319            String... attributeDescriptions);
1320
1321    /**
1322     * Asynchronously searches the Directory Server using the provided search
1323     * request.
1324     *
1325     * @param request
1326     *            The search request.
1327     * @param entryHandler
1328     *            A search result handler which can be used to asynchronously
1329     *            process the search result entries and references as they are
1330     *            received, may be {@code null}.
1331     * @return A promise representing the result of the operation.
1332     * @throws UnsupportedOperationException
1333     *             If this connection does not support search operations.
1334     * @throws IllegalStateException
1335     *             If this connection has already been closed, i.e. if
1336     *             {@code isClosed() == true}.
1337     * @throws NullPointerException
1338     *             If {@code request} was {@code null}.
1339     */
1340    LdapPromise<Result> searchAsync(SearchRequest request, SearchResultHandler entryHandler);
1341
1342    /**
1343     * Asynchronously searches the Directory Server using the provided search
1344     * request.
1345     *
1346     * @param request
1347     *            The search request.
1348     * @param intermediateResponseHandler
1349     *            An intermediate response handler which can be used to process
1350     *            any intermediate responses as they are received, may be
1351     *            {@code null}.
1352     * @param entryHandler
1353     *            A search result handler which can be used to asynchronously
1354     *            process the search result entries and references as they are
1355     *            received, may be {@code null}.
1356     * @return A promise representing the result of the operation.
1357     * @throws UnsupportedOperationException
1358     *             If this connection does not support search operations.
1359     * @throws IllegalStateException
1360     *             If this connection has already been closed, i.e. if
1361     *             {@code isClosed() == true}.
1362     * @throws NullPointerException
1363     *             If {@code request} was {@code null}.
1364     */
1365    LdapPromise<Result> searchAsync(SearchRequest request, IntermediateResponseHandler intermediateResponseHandler,
1366        SearchResultHandler entryHandler);
1367
1368    /**
1369     * Searches the Directory Server for a single entry using the provided
1370     * search request.
1371     * <p>
1372     * If the requested entry is not returned by the Directory Server then the
1373     * request will fail with an {@link EntryNotFoundException}. More
1374     * specifically, this method will never return {@code null}. If multiple
1375     * matching entries are returned by the Directory Server then the request
1376     * will fail with an {@link MultipleEntriesFoundException}.
1377     *
1378     * @param request
1379     *            The search request.
1380     * @return The single search result entry returned from the search.
1381     * @throws LdapException
1382     *             If the result code indicates that the request failed for some
1383     *             reason.
1384     * @throws UnsupportedOperationException
1385     *             If this connection does not support search operations.
1386     * @throws IllegalStateException
1387     *             If this connection has already been closed, i.e. if
1388     *             {@code isClosed() == true}.
1389     * @throws NullPointerException
1390     *             If the {@code request} was {@code null}.
1391     */
1392    SearchResultEntry searchSingleEntry(SearchRequest request) throws LdapException;
1393
1394    /**
1395     * Searches the Directory Server for a single entry using the provided
1396     * search parameters.
1397     * <p>
1398     * If the requested entry is not returned by the Directory Server then the
1399     * request will fail with an {@link EntryNotFoundException}. More
1400     * specifically, this method will never return {@code null}. If multiple
1401     * matching entries are returned by the Directory Server then the request
1402     * will fail with an {@link MultipleEntriesFoundException}.
1403     * <p>
1404     * This method is equivalent to the following code:
1405     *
1406     * <pre>
1407     * SearchRequest request = new SearchRequest(baseObject, scope, filter, attributeDescriptions);
1408     * connection.searchSingleEntry(request);
1409     * </pre>
1410     *
1411     * @param baseObject
1412     *            The distinguished name of the base entry relative to which the
1413     *            search is to be performed.
1414     * @param scope
1415     *            The scope of the search.
1416     * @param filter
1417     *            The filter that defines the conditions that must be fulfilled
1418     *            in order for an entry to be returned.
1419     * @param attributeDescriptions
1420     *            The names of the attributes to be included with each entry.
1421     * @return The single search result entry returned from the search.
1422     * @throws LdapException
1423     *             If the result code indicates that the request failed for some
1424     *             reason.
1425     * @throws LocalizedIllegalArgumentException
1426     *             If {@code baseObject} could not be decoded using the default
1427     *             schema or if {@code filter} is not a valid LDAP string
1428     *             representation of a filter.
1429     * @throws UnsupportedOperationException
1430     *             If this connection does not support search operations.
1431     * @throws IllegalStateException
1432     *             If this connection has already been closed, i.e. if
1433     *             {@code isClosed() == true}.
1434     * @throws NullPointerException
1435     *             If the {@code baseObject}, {@code scope}, or {@code filter}
1436     *             were {@code null}.
1437     */
1438    SearchResultEntry searchSingleEntry(String baseObject, SearchScope scope, String filter,
1439            String... attributeDescriptions) throws LdapException;
1440
1441    /**
1442     * Asynchronously searches the Directory Server for a single entry using the
1443     * provided search request.
1444     * <p>
1445     * If the requested entry is not returned by the Directory Server then the
1446     * request will fail with an {@link EntryNotFoundException}. More
1447     * specifically, the returned promise will never return {@code null}. If
1448     * multiple matching entries are returned by the Directory Server then the
1449     * request will fail with an {@link MultipleEntriesFoundException}.
1450     *
1451     * @param request
1452     *            The search request.
1453     * @return A promise representing the result of the operation.
1454     * @throws UnsupportedOperationException
1455     *             If this connection does not support search operations.
1456     * @throws IllegalStateException
1457     *             If this connection has already been closed, i.e. if
1458     *             {@code isClosed() == true}.
1459     * @throws NullPointerException
1460     *             If the {@code request} was {@code null}.
1461     */
1462    LdapPromise<SearchResultEntry> searchSingleEntryAsync(SearchRequest request);
1463}