in the searchResultDone message; include the sortKeyResponseControl in
the searchResultDone message, and not send back any search result
entries.
*/
searchOperation.addResponseControl(
new ServerSideSortResponseControl(
LDAPResultCode.NO_SUCH_ATTRIBUTE, null));
searchOperation.setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
return;
}
VLVRequestControl vlvRequest = searchOperation
.getRequestControl(VLVRequestControl.DECODER);
if (vlvRequest != null && pageRequest != null)
{
Message message = ERR_JEB_SEARCH_CANNOT_MIX_PAGEDRESULTS_AND_VLV.get();
throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
}
// Handle client abandon of paged results.
if (pageRequest != null)
{
if (pageRequest.getSize() == 0)
{
PagedResultsControl control;
control = new PagedResultsControl(pageRequest.isCritical(), 0, null);
searchOperation.getResponseControls().add(control);
return;
}
if (searchOperation.getSizeLimit() > 0 &&
pageRequest.getSize() >= searchOperation.getSizeLimit())
{
// The RFC says : "If the page size is greater than or equal to the
// sizeLimit value, the server should ignore the control as the
// request can be satisfied in a single page"
pageRequest = null;
}
}
// Handle base-object search first.
if (searchScope == SearchScope.BASE_OBJECT)
{
// Fetch the base entry.
Entry baseEntry = null;
try
{
baseEntry = getEntry(baseDN);
}
catch (Exception e)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
}
// The base entry must exist for a successful result.
if (baseEntry == null)
{
// Check for referral entries above the base entry.
dn2uri.targetEntryReferrals(baseDN, searchScope);
Message message = ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(baseDN.toString());
DN matchedDN = getMatchedDN(baseDN);
throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
message, matchedDN, null);
}
if (!isManageDsaITOperation(searchOperation))
{
dn2uri.checkTargetForReferral(baseEntry, searchOperation.getScope());
}
if (searchOperation.getFilter().matchesEntry(baseEntry))
{
searchOperation.returnEntry(baseEntry, null);
}
if (pageRequest != null)
{
// Indicate no more pages.
PagedResultsControl control;
control = new PagedResultsControl(pageRequest.isCritical(), 0, null);
searchOperation.getResponseControls().add(control);
}
return;
}
// Check whether the client requested debug information about the
// contribution of the indexes to the search.
StringBuilder debugBuffer = null;
if (searchOperation.getAttributes().contains(ATTR_DEBUG_SEARCH_INDEX))
{
debugBuffer = new StringBuilder();
}
EntryIDSet entryIDList = null;
boolean candidatesAreInScope = false;
if(sortRequest != null)
{
for(VLVIndex vlvIndex : vlvIndexMap.values())
{
try
{
entryIDList =
vlvIndex.evaluate(null, searchOperation, sortRequest, vlvRequest,
debugBuffer);
if(entryIDList != null)
{
searchOperation.addResponseControl(
new ServerSideSortResponseControl(LDAPResultCode.SUCCESS,
null));
candidatesAreInScope = true;
break;
}
}
catch (DirectoryException de)
{
searchOperation.addResponseControl(
new ServerSideSortResponseControl(
de.getResultCode().getIntValue(), null));
if (sortRequest.isCritical())
{
throw de;
}
}
}
}
if(entryIDList == null)
{
// Create an index filter to get the search result candidate entries.
IndexFilter indexFilter =
new IndexFilter(this, searchOperation, debugBuffer,
rootContainer.getMonitorProvider());
// Evaluate the filter against the attribute indexes.
entryIDList = indexFilter.evaluate();
// Evaluate the search scope against the id2children and id2subtree
// indexes.
if (entryIDList.size() > IndexFilter.FILTER_CANDIDATE_THRESHOLD)
{
// Read the ID from dn2id.
EntryID baseID = dn2id.get(null, baseDN, LockMode.DEFAULT);
if (baseID == null)
{
Message message =
ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(baseDN.toString());
DN matchedDN = getMatchedDN(baseDN);
throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
message, matchedDN, null);
}
DatabaseEntry baseIDData = baseID.getDatabaseEntry();
EntryIDSet scopeList;
if (searchScope == SearchScope.SINGLE_LEVEL)
{
scopeList = id2children.readKey(baseIDData, null, LockMode.DEFAULT);
}
else
{
scopeList = id2subtree.readKey(baseIDData, null, LockMode.DEFAULT);
if (searchScope == SearchScope.WHOLE_SUBTREE)
{
// The id2subtree list does not include the base entry ID.
scopeList.add(baseID);
}
}
entryIDList.retainAll(scopeList);
if (debugBuffer != null)
{
debugBuffer.append(" scope=");
debugBuffer.append(searchScope);
scopeList.toString(debugBuffer);
}
if (scopeList.isDefined())
{
// In this case we know that every candidate is in scope.
candidatesAreInScope = true;
}
}
if (sortRequest != null)
{
try
{
//If the sort key is not present, the sorting will generate the
//default ordering. VLV search request goes through as if
//this sort key was not found in the user entry.
entryIDList = EntryIDSetSorter.sort(this, entryIDList,
searchOperation,
sortRequest.getSortOrder(),
vlvRequest);
if(sortRequest.containsSortKeys())
{
searchOperation.addResponseControl(
new ServerSideSortResponseControl(
LDAPResultCode.SUCCESS, null));
}
else
{
/*
There is no sort key associated with the sort control. Since it
came here it means that the critificality is false so let the
server return all search results unsorted and include the
sortKeyResponseControl inthe searchResultDone message.
*/
searchOperation.addResponseControl(
new ServerSideSortResponseControl
(LDAPResultCode.NO_SUCH_ATTRIBUTE, null));
}
}
catch (DirectoryException de)
{
searchOperation.addResponseControl(
new ServerSideSortResponseControl(
de.getResultCode().getIntValue(), null));
if (sortRequest.isCritical())
{
throw de;
}
}
}
}
// If requested, construct and return a fictitious entry containing
// debug information, and no other entries.
if (debugBuffer != null)
{
debugBuffer.append(" final=");
entryIDList.toString(debugBuffer);
Attribute attr = Attributes.create(ATTR_DEBUG_SEARCH_INDEX,
debugBuffer.toString());
Entry debugEntry;
debugEntry = new Entry(DN.decode("cn=debugsearch"), null, null, null);
debugEntry.addAttribute(attr, new ArrayList<AttributeValue>());
searchOperation.returnEntry(debugEntry, null);
return;
}
if (entryIDList.isDefined())
{
if(rootContainer.getMonitorProvider().isFilterUseEnabled())
{
rootContainer.getMonitorProvider().updateIndexedSearchCount();
}
searchIndexed(entryIDList, candidatesAreInScope, searchOperation,
pageRequest);
}
else
{
if(rootContainer.getMonitorProvider().isFilterUseEnabled())
{
rootContainer.getMonitorProvider().updateUnindexedSearchCount();
}
// See if we could use a virtual attribute rule to process the search.
for (VirtualAttributeRule rule : DirectoryServer.getVirtualAttributes())
{
if (rule.getProvider().isSearchable(rule, searchOperation))
{
rule.getProvider().processSearch(rule, searchOperation);
return;
}
}
ClientConnection clientConnection =
searchOperation.getClientConnection();
if(! clientConnection.hasPrivilege(Privilege.UNINDEXED_SEARCH,
searchOperation))
{
Message message =
ERR_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES.get();
throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
message);
}
if (sortRequest != null)
{
// FIXME -- Add support for sorting unindexed searches using indexes
// like DSEE currently does.
searchOperation.addResponseControl(
new ServerSideSortResponseControl(
LDAPResultCode.UNWILLING_TO_PERFORM, null));
if (sortRequest.isCritical())
{
Message message = ERR_JEB_SEARCH_CANNOT_SORT_UNINDEXED.get();