Asynchronous Searching

Ldaptive provides support for executing asynchronous searches, although some providers do not support all the LDAP features. It is recommended to use either the UnboundID, Apache, or JLDAP providers. JNDI does not support any asynchronous operations.

If your goal is to execute non-blocking searches, also consider using one of the implementations in the concurrent package.

Connection conn = DefaultConnectionFactory.getConnection("ldap://directory.ldaptive.org");
try {
conn.open();
AsyncSearchOperation search = new AsyncSearchOperation(conn);
SearchRequest request = new SearchRequest("ou=people,dc=ldaptive,dc=org", "(cn=*fisher)");
FutureResponse<SearchResult> response = search.execute(request);

// block until response arrives
SearchResult result = response.getResult();

// cleanup the underlying executor service
search.shutdown();

} finally {
conn.close();
}

Various handlers provide the hooks for receiving asynchronous events if you want to operate on results before the response is received. Of particular importance is the AsyncRequest object. If you wish to abandon or cancel the async operation you will need to obtain a reference to it. This reference is obtained by setting an AsyncRequestHandler. A single AsyncRequest is produced for each search execution.

Connection conn = DefaultConnectionFactory.getConnection("ldap://directory.ldaptive.org");
try {
conn.open();
AsyncSearchOperation search = new AsyncSearchOperation(conn);
final BlockingQueue<AsyncRequest> queue = new LinkedBlockingQueue<AsyncRequest>();

// do something when a response is received
search.setOperationResponseHandlers(
new OperationResponseHandler<SearchRequest, SearchResult>() {
@Override
public HandlerResult<Response<SearchResult>> handle(
Connection conn, SearchRequest request, Response<SearchResult> response)
throws LdapException
{
System.err.println("received: " + response);
return new HandlerResult<Response<SearchResult>>(response);
}
});

// if you plan to cancel or abandon this operation you need a reference to the AsyncRequest
search.setAsyncRequestHandlers(
new AsyncRequestHandler() {
@Override
public HandlerResult<AsyncRequest> handle(
Connection conn, Request request, AsyncRequest asyncRequest)
throws LdapException
{
queue.add(asyncRequest);
return new HandlerResult<AsyncRequest>(asyncRequest);
}
});

// long running searches may experience problems, do something when an exception occurs
search.setExceptionHandler(
new ExceptionHandler() {
@Override
public HandlerResult<Exception> handle(
Connection conn, Request request, Exception exception)
{
System.err.println("received exception: " + exception);
return new HandlerResult<Exception>(null);
}
});

SearchRequest request = new SearchRequest("ou=people,dc=ldaptive,dc=org", "(cn=*fisher)");
// do something when an entry is received
request.setSearchEntryHandlers(
new SearchEntryHandler() {
@Override
public HandlerResult<SearchEntry> handle(
Connection conn, SearchRequest request, SearchEntry entry)
throws LdapException
{
System.err.println("received: " + entry);
// return null value in the handler result to prevent the entry from being stored in the SearchResult
return new HandlerResult<SearchEntry>(entry);
}
@Override
public void initializeRequest(final SearchRequest request) {}
});

FutureResponse<SearchResult> response = search.execute(request);

// wait for the async handle
AsyncRequest asyncRequest = queue.take();

// now you can abandon the operation
asyncRequest.abandon();

// or cancel the operation
CancelOperation cancel = new CancelOperation(conn);
cancel.execute(new CancelRequest(asyncRequest.getMessageId()));

// or just block until the response arrives
SearchResult result = response.getResult();

// cleanup the underlying executor service
search.shutdown();

} finally {
conn.close();
}