/* See LICENSE for licensing and NOTICE for copyright. */
package org.ldaptive;
import org.ldaptive.cache.Cache;
import org.ldaptive.handler.HandlerResult;
import org.ldaptive.intermediate.IntermediateResponse;
import org.ldaptive.provider.SearchItem;
import org.ldaptive.provider.SearchIterator;
/**
* Executes an ldap search operation.
*
* @author Middleware Services
*/
public class SearchOperation extends AbstractOperation<SearchRequest, SearchResult>
{
/** Cache to use when performing searches. */
private Cache<SearchRequest> cache;
/**
* Creates a new search operation.
*
* @param conn connection
*/
public SearchOperation(final Connection conn)
{
super(conn);
}
/**
* Creates a new search operation.
*
* @param conn connection
* @param c cache
*/
public SearchOperation(final Connection conn, final Cache<SearchRequest> c)
{
super(conn);
cache = c;
}
/**
* Returns the cache to check when performing search operations. When a cache is provided it will be populated as new
* searches are performed and used when a search request hits the cache.
*
* @return cache
*/
public Cache<SearchRequest> getCache()
{
return cache;
}
/**
* Sets the cache.
*
* @param c cache to set
*/
public void setCache(final Cache<SearchRequest> c)
{
cache = c;
}
@Override
protected Response<SearchResult> invoke(final SearchRequest request)
throws LdapException
{
Response<SearchResult> response;
if (cache != null) {
final SearchResult sr = cache.get(request);
if (sr == null) {
response = executeSearch(request);
cache.put(request, response.getResult());
logger.debug("invoke stored result={} in cache", response.getResult());
} else {
logger.debug("invoke found result={} in cache", sr);
response = new Response<>(sr, null);
}
} else {
response = executeSearch(request);
}
return response;
}
/**
* Performs the ldap search.
*
* @param request to invoke search with
*
* @return ldap response
*
* @throws LdapException if an error occurs
*/
protected Response<SearchResult> executeSearch(final SearchRequest request)
throws LdapException
{
final SearchIterator si = getConnection().getProviderConnection().search(request);
final SearchResult result = readResult(request, si);
final Response<Void> response = si.getResponse();
return
new Response<>(
result,
response.getResultCode(),
response.getMessage(),
response.getMatchedDn(),
response.getControls(),
response.getReferralURLs(),
response.getMessageId());
}
/**
* Invokes the provider search operation and iterates over the results. Invokes handlers as necessary for each result
* type.
*
* @param request used to create the search iterator
* @param si search iterator
*
* @return search result
*
* @throws LdapException if an error occurs
*/
protected SearchResult readResult(final SearchRequest request, final SearchIterator si)
throws LdapException
{
final SearchResult result = new SearchResult(request.getSortBehavior());
try {
while (si.hasNext()) {
final SearchItem item = si.next();
logger.trace("Received search item={}", item);
if (item.isSearchEntry()) {
final SearchEntry se = item.getSearchEntry();
if (se != null) {
final HandlerResult<SearchEntry> hr = executeHandlers(request.getSearchEntryHandlers(), request, se);
if (hr.getResult() != null) {
result.addEntry(hr.getResult());
}
if (hr.getAbort()) {
logger.debug("Aborting search on entry=%s", se);
break;
}
}
} else if (item.isSearchReference()) {
final SearchReference sr = item.getSearchReference();
if (sr != null) {
final HandlerResult<SearchReference> hr = executeHandlers(
request.getSearchReferenceHandlers(),
request,
sr);
if (hr.getResult() != null) {
final SearchReference reference = hr.getResult();
final Response<SearchResult> refResponse = reference.getReferenceResponse();
if (refResponse != null) {
if (refResponse.getResultCode() == ResultCode.SUCCESS) {
result.addEntries(refResponse.getResult().getEntries());
} else {
result.addReference(reference);
}
} else {
result.addReference(reference);
}
}
if (hr.getAbort()) {
logger.debug("Aborting search on reference=%s", sr);
break;
}
}
} else if (item.isIntermediateResponse()) {
final IntermediateResponse ir = item.getIntermediateResponse();
if (ir != null) {
final HandlerResult<IntermediateResponse> hr = executeHandlers(
request.getIntermediateResponseHandlers(),
request,
ir);
if (hr.getAbort()) {
logger.debug("Aborting search on intermediate response=%s", ir);
break;
}
}
}
}
} finally {
si.close();
}
return result;
}
}