The solution for me was to implement a custom DirContextProcessor that allowed me to sort on multiple attributes with the desired direction (ascending/descending) by making use of the overload method of the SortControl class that takes an array of SortKeys objects as a parameter.
The implementation must extend the AbstractFallbackRequestAndResponseControlDirContextProcessor and override the createRequestControl method.
The superclass AbstractFallbackRequestAndResponseControlDirContextProcessor will take care of the actual creation of the control. It only expects 2 pieces of information from the subclass.
- The fully qualified class name of the control to instantiate
- The types and values of the constructor parameters
The fully qualified class name is provided in the subclass property defaultRequestControl, and the types and values of the constructor parameters are provided in the subclass method createRequestControl.
The information of the sorting direction for any particular attribute is provided in the ascendingOrder property of the SortKey object.
public class SortMultipleControlDirContextProcessor extends AbstractFallbackRequestAndResponseControlDirContextProcessor{
private SortKey[] sortKeys;
private boolean sorted;
private int resultCode;
public SortMultipleControlDirContextProcessor(SortKey ... sortKeys){
if(ArrayUtils.isEmpty(sortKeys)){
throw new IllegalArgumentException("At least one key to sort on must be provided.");
}
this.sortKeys = sortKeys;
this.sorted = false;
this.resultCode = -1;
this.defaultRequestControl = "javax.naming.ldap.SortControl";
this.defaultResponseControl = "javax.naming.ldap.SortResponseControl";
this.fallbackRequestControl = "com.sun.jndi.ldap.ctl.SortControl";
this.fallbackResponseControl = "com.sun.jndi.ldap.ctl.SortResponseControl";
loadControlClasses();
}
@Override
public Control createRequestControl(){
return super.createRequestControl(new Class[]{SortKey[].class, boolean.class}, new Object[]{sortKeys, critical});
}
@Override
protected void handleResponse(Object control) {
Boolean result = (Boolean) invokeMethod("isSorted", responseControlClass, control);
this.sorted = result;
Integer code = (Integer) invokeMethod("getResultCode", responseControlClass, control);
this.resultCode = code;
}
public SortKey[] getSortKeys(){
return sortKeys;
}
public boolean isSorted(){
return sorted;
}
public int getResultCode(){
return resultCode;
}
}
After the implementation, you can use the class to sort the results on multiple attributes in any desired direction:
// SortKey for sorting results on the cn attribute in descending order
SortKey cnSortKey = new SortKey("cn", false, null);
// Instantiate the control
SortMultipleControlDirContextProcessor myCustomControl = new SortMultipleControlDirContextProcessor(cnSortKey);
// Perform the search with the control
List<User> users = ldapTemplate.search("", orFilter.encode(), searchControls, new UserAttributesMapper(), myCustomControl);