/* See LICENSE for licensing and NOTICE for copyright. */
package org.ldaptive.templates;
import java.util.Arrays;
import java.util.Collection;
import org.ldaptive.LdapEntry;
import org.ldaptive.LdapException;
import org.ldaptive.Response;
import org.ldaptive.SearchFilter;
import org.ldaptive.SearchResult;
import org.ldaptive.SortBehavior;
import org.ldaptive.concurrent.AggregatePooledSearchExecutor;
import org.ldaptive.pool.PooledConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Searches an LDAP using a defined set of search templates. For each term count some number of templates are defined
* and used for searching.
*
* @author Middleware Services
*/
public class SearchTemplatesExecutor
{
/** Logger for this class. */
protected final Logger logger = LoggerFactory.getLogger(getClass());
/** Search executor. */
private AggregatePooledSearchExecutor searchExecutor;
/** Connection factory. */
private PooledConnectionFactory[] connectionFactories;
/** Search templates. */
private SearchTemplates[] searchTemplates;
/** Default constructor. */
public SearchTemplatesExecutor() {}
/**
* Creates a new templates search executor.
*
* @param executor aggregate pooled search executor
* @param factories pooled connection factories
* @param templates search templates
*/
public SearchTemplatesExecutor(
final AggregatePooledSearchExecutor executor,
final PooledConnectionFactory[] factories,
final SearchTemplates... templates)
{
searchExecutor = executor;
connectionFactories = factories;
searchTemplates = templates;
}
/**
* Returns the search executor.
*
* @return aggregate pooled search executor
*/
public AggregatePooledSearchExecutor getSearchExecutor()
{
return searchExecutor;
}
/**
* Sets the search executor.
*
* @param executor aggregate pooled search executor
*/
public void setSearchExecutor(final AggregatePooledSearchExecutor executor)
{
searchExecutor = executor;
}
/**
* Returns the connection factories.
*
* @return pooled connection factories
*/
public PooledConnectionFactory[] getConnectionFactories()
{
return connectionFactories;
}
/**
* Sets the connection factories.
*
* @param factories pooled connection factory
*/
public void setConnectionFactories(final PooledConnectionFactory[] factories)
{
connectionFactories = factories;
}
/**
* Returns the search templates.
*
* @return search templates
*/
public SearchTemplates[] getSearchTemplates()
{
return searchTemplates;
}
/**
* Sets the search templates.
*
* @param templates search templates
*/
public void setSearchTemplates(final SearchTemplates[] templates)
{
searchTemplates = templates;
}
/**
* Applies the supplied query to a search templates and aggregates all results into a single search result.
*
* @param query to execute
*
* @return ldap result
*
* @throws LdapException if the search fails
*/
public SearchResult search(final Query query)
throws LdapException
{
logger.debug("Query: {}", query);
// get a search object
SearchTemplates templates = null;
if (query.getTerms().length > 0) {
logger.debug("Processing query: {}", Arrays.toString(query.getTerms()));
int termCount = query.getTerms().length;
// if term count exceeds the highest defined templates
// use the highest set of templates available
if (termCount > searchTemplates.length) {
termCount = searchTemplates.length;
}
if (termCount > 0) {
templates = searchTemplates[termCount - 1];
if (templates != null) {
logger.debug("Found search templates {} for term count of {}", templates, termCount);
} else {
logger.debug("No search module found for term count of {}", termCount);
}
} else {
logger.debug("No terms found in query {}", query);
}
}
if (templates != null) {
return search(templates.format(query), query.getReturnAttributes(), query.getFromResult(), query.getToResult());
} else {
return null;
}
}
/**
* Performs an LDAP search with the supplied filters and aggregates all the search results together.
*
* @param filters to execute
* @param returnAttrs attributes to return from the search
* @param fromResult index to return results from
* @param toResult index to return results to
*
* @return ldap result containing all results
*
* @throws LdapException if the search fails
*/
protected SearchResult search(
final SearchFilter[] filters,
final String[] returnAttrs,
final Integer fromResult,
final Integer toResult)
throws LdapException
{
logger.debug("Performing search with {} filters", Arrays.toString(filters));
// perform parallel searches
final Collection<Response<SearchResult>> responses = searchExecutor.search(
connectionFactories,
filters,
returnAttrs);
// iterate over all results and store each entry
final SearchResult result = new SearchResult(SortBehavior.ORDERED);
for (Response<SearchResult> r : responses) {
for (LdapEntry le : r.getResult().getEntries()) {
result.addEntry(le);
logger.debug("Search found: {}", le.getDn());
}
}
SearchResult subResult;
if (fromResult != null) {
if (toResult != null) {
subResult = result.subResult(fromResult, toResult);
} else {
subResult = result.subResult(fromResult, result.size());
}
} else if (toResult != null) {
subResult = result.subResult(0, toResult);
} else {
subResult = result;
}
return subResult;
}
/** Closes any resources associated with this object. */
public void close()
{
if (connectionFactories != null) {
for (PooledConnectionFactory factory : connectionFactories) {
factory.getConnectionPool().close();
}
}
}
@Override
public String toString()
{
return
String.format(
"[%s@%d::searchExecutor=%s, connectionFactories=%s, " +
"searchTemplates=%s]",
getClass().getName(),
hashCode(),
searchExecutor,
Arrays.toString(connectionFactories),
Arrays.toString(searchTemplates));
}
}