Author |
Topic: LDAP Search Paged Results Control |
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
LDAP Search Paged Results Control |
This control may be useful when the LDAP client has limited resources and may not be able to process the entire result set from a given LDAP query, or when the LDAP client is connected over a low-bandwidth connection.
The structure of this control is as follows:
pagedResultsControl ::= SEQUENCE {
controlType 1.2.840.113556.1.4.319,
criticality BOOLEAN DEFAULT FALSE,
controlValue searchControlValue
}
The searchControlValue is an OCTET STRING wrapping the BER-encoded version of the following SEQUENCE:
realSearchControlValue ::= SEQUENCE {
size INTEGER (0..maxInt),
-- requested page size from client
-- result set size estimate from server
cookie OCTET STRING
}
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
LDAP Search Paged Results Control JNDI Client |
The following example shows how a client performs Paged Results Control to interact with server.
/**
*
* PagedResultsControlJndiClient.java
* Sample code to demostrate how Paged Results Control works.
*
*/
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import java.util.Hashtable;
public class PagedResultsControlJndiClient
{
static final String PAGED_RESULT_CONTROL_OID = "1.2.840.113556.1.4.319";
public static void main(String[] args)
{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
// Note: Active Directory Server supports Paged Results Control
// SunOne does not supports Paged Results Control but it supports
// Virtual List View Control instead.
env.put(Context.PROVIDER_URL, "ldap://myAD.mydomain.com:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "administrator@mydomain.com");
env.put(Context.SECURITY_CREDENTIALS, "mypassword");
try{
/* Open an LDAP connection for the provided principal and credentials */
LdapContext ctx = new InitialLdapContext(env, null);
System.out.println("Initial binding done!");
/* Query the server to see if the paged result control is supported */
if(!isPagedResultControlSupported(ctx)){
System.out.println("The server does not support Paged Results Control.");
System.exit(1);
}
/* Activate paged results */
int pageSize = 5;
byte[] cookie = null;
int total;
ctx.setRequestControls(
new Control[]{new PagedResultsControl(pageSize, Control.CRITICAL)});
System.out.println("Paged control set!");
int count = 0;
while(true){
count++;
System.err.println("Search loop count = " + count);
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
ctls.setCountLimit(0);
// Perform the search
NamingEnumeration results = ctx.search("dc=mydomain,dc=com",
"(objectclass=*)", ctls);
try{
// Iterate over a batch of search results
while (results != null && results.hasMore()) {
// Display an entry
SearchResult entry = (SearchResult)results.next();
System.out.println("entryDN=" + entry.getName());
}
}catch(Exception pe){
System.out.println(pe.toString()); // Patial Result Exception
}
// Examine the paged results control response
Control[] controls = ctx.getResponseControls();
if(controls!=null){
for(int k = 0; k<controls.length; k++){
if(controls[k] instanceof PagedResultsResponseControl){
PagedResultsResponseControl prrc =
(PagedResultsResponseControl)controls[k];
total = prrc.getResultSize();
cookie = prrc.getCookie();
}else{
// Handle other response controls (if any)
}
}
}
if(cookie==null)
break;
// Re-activate paged results
ctx.setRequestControls(new Control[]{
new PagedResultsControl(pageSize, cookie, Control.CRITICAL)});
}
// Close the LDAP association
ctx.close();
}catch (Exception e){
e.printStackTrace();
}
}
/**
* Is paged result control supported?
*
* Query the rootDSE object to find out if the paged result control
* is supported.
*/
static boolean isPagedResultControlSupported(LdapContext ctx)
throws NamingException
{
SearchControls ctl = new SearchControls();
ctl.setReturningAttributes(new String[]{"supportedControl"});
ctl.setSearchScope(SearchControls.OBJECT_SCOPE);
/* search for the rootDSE object */
NamingEnumeration results = ctx.search("", "(objectClass=*)", ctl);
while(results.hasMore()){
SearchResult entry = (SearchResult)results.next();
NamingEnumeration attrs = entry.getAttributes().getAll();
while (attrs.hasMore()){
Attribute attr = (Attribute)attrs.next();
NamingEnumeration vals = attr.getAll();
while (vals.hasMore()){
String value = (String) vals.next();
if(value.equals(PAGED_RESULT_CONTROL_OID))
return true;
}
}
}
return false;
}
}
The above code has been tested against Active Directory 2000 and 2003.
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
OperationNotSupportedException |
If you run the above client against LDAP servers which do not support Paged Results Control, most likely you are going to get error message similar like this.
javax.naming.OperationNotSupportedException from SunOne Directory Server:
javax.naming.OperationNotSupportedException: [LDAP: error code 12 - Unavailable Critical Extension]; remaining name 'dc=mydomain,dc=com' at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3045) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2931) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2737) at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1808) at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1731) at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:368) at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:338) at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:321) at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:248)
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
How does client discard unwanted results in process? |
A sequence of paged search requests is abandoned by the client: sending a search request containing a pagedResultsControl with the size set to zero (pageSize=0). sending an LDAP Abandon operation to abandon one paged search request in progress, but this is discouraged. walking away without informing server, definitely this is strongly discouraged.
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
What happens if pageSize > MaxPageSize ? |
Take AD for example, its MaxPageSize = 1000 by default, which means each search cannot return results more than 1000. The problem is that you might have no idea of the value of MaxPageSize for a given LDAP server and you might accidentally set pageSize > MaxPageSize, e.g. 1500 > 1000.
AD will automatically trim the 1500 to 1000 and return only 1000 results each page. That's OK and doesn't hurts anyone.
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
What happens if pageSize > sizeLimit ? |
For a given search, there is always a bound size limit, either 0 or something. For the value of 0 which means no limit, it's OK for any value of pageSize. For sizeLimit !=0, if pageSize <= sizeLimit, it's still OK, but if pageSize > sizeLimit, you would get something like this:
javax.naming.SizeLimitExceededException: [LDAP: error code 4 - Sizelimit Exceeded]; remaining name 'dc=mydomain,dc=com'
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
What happens if pageSize < sizeLimit ? |
'sizeLimit' will be ignored by nature.
Search Paged Results Control is per operation rather than connection. When you associate the Search Paged Results Control with a search, you expect the number of results returned is governed by 'pageSize' -- the 'sizeLimit' is therefore useless for this search.
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
What happens if client sends request again and again? |
A client may have any number of outstanding search requests pending,
any of which may have used the pagedResultsControl. A server
implementation which requires a limit on the number of outstanding
paged search requests from a given client MAY either return
unwillingToPerform when the client attempts to create a new paged
search request, or age out an older result set. If the server
implementation ages out an older paged search request, it SHOULD
return "unwilling to perform" if the client attempts to resume the
paged search that was aged out.
In order to serve the PagedResultsControl, the serve may have to prepare and hold the whole result set on the server side for each client associated a cookie. If a client open too many requests and leave them open without consuming the results, this will be a burden on server and might choke the server. In that sense, the server can defense itself by aged out the previous requests for the specific client.
|
|
|
|
|
|
|
Naziya member offline |
|
posts: |
3 |
joined: |
01/26/2012 |
from: |
Bangalore, Karnataka India |
|
|
|
|
|
|
Thanks. It worked fine serving the purpose and saved my time. :-) |
|
|
|
|
|
|
Naziya member offline |
|
posts: |
3 |
joined: |
01/26/2012 |
from: |
Bangalore, Karnataka India |
|
|
|
|
|
SizelimitException |
Thanks. It worked fine serving the purpose and saved my time. :-) |
|
|
|
|
|
|
Naziya member offline |
|
posts: |
3 |
joined: |
01/26/2012 |
from: |
Bangalore, Karnataka India |
|
|
|
|
|
SizeLimitException |
Thanks. Worked fine for me serving the purpose and saved my time :-) |
|
|
|
|
|
|
ziaur22311 member offline |
|
posts: |
4 |
joined: |
02/23/2012 |
from: |
Lausanne, Switzerland Switzerland |
|
|
|
|
|
I get a no controls were sent from te server. |
The code loooks good, but how to proceed when LDAP servers do not support Paged Results Control. Rather how to fetch large records from (>1000) from LDAP.
Also how does one know, what type of LDAP server, we are communicating with.
I do not get the PagedResultsResponseControl object from the ccontext, any help would be appreciated. |
|
|
|
|
|
|
ziaur22311 member offline |
|
posts: |
4 |
joined: |
02/23/2012 |
from: |
Lausanne, Switzerland Switzerland |
|
|
|
|
|
LimitExceededException |
When i set the sdeaxr scope to SearchControls.SUBTREE_SCOPE...
I get the following exception..
javax.naming.LimitExceededException: [LDAP: error code 11 - Administrative Limit Exceeded]; remaining name 'ou=larcAccs,ou=WI,ou=larcAppls,ou=AURA,ou=Credit Suisse,o=CREDIT SUISSE GROUP' at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3126) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2987) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2794) at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:129) at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:198) at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:171) at PagedSearch.main(PagedSearch.java:76) |
|
|
|
|
|
|
ziaur22311 member offline |
|
posts: |
4 |
joined: |
02/23/2012 |
from: |
Lausanne, Switzerland Switzerland |
|
|
|
|
|
LimitExceededException |
When i set the sdeaxr scope to SearchControls.SUBTREE_SCOPE...
I get the following exception..
javax.naming.LimitExceededException: [LDAP: error code 11 - Administrative Limit Exceeded]; remaining name 'ou=larcAccs,ou=WI,ou=larcAppls,ou=AURA,ou=Credit Suisse,o=CREDIT SUISSE GROUP' at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3126) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2987) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2794) at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:129) at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:198) at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:171) at PagedSearch.main(PagedSearch.java:76) |
|
|
|
|
|
|
ziaur22311 member offline |
|
posts: |
4 |
joined: |
02/23/2012 |
from: |
Lausanne, Switzerland Switzerland |
|
|
|
|
|
LimitExceededException |
When i set the sdeaxr scope to SearchControls.SUBTREE_SCOPE...
I get the following exception..
javax.naming.LimitExceededException: [LDAP: error code 11 - Administrative Limit Exceeded]; remaining name 'ou=larcAccs,ou=WI,ou=larcAppls,ou=AURA,ou=Credit Suisse,o=CREDIT SUISSE GROUP' at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3126) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2987) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2794) at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:129) at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:198) at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:171) at PagedSearch.main(PagedSearch.java:76) |
|
|
|
|
|
|
krithiga member offline |
|
posts: |
|
joined: |
05/03/2012 |
from: |
Karanataka India |
|
|
|
|
|
LDAP paged result control |
I have a requirement the i need to fetch all the records from AD even if it is more than 1000 entries. I tried using PagedResult control (from net) it works fine for filter which has less than 1000 entries. But if the filter fetches more than 1000 (that is needed)
(JAVA) result is namingEnumeration
results.hasmore loop returns false and not going in to the loop.
What would be the reason it is failing?
Very urgent.Please help me in this regard.
Using the same code as above. |
|
|
|
|
|
|
krithiga member offline |
|
posts: |
|
joined: |
05/03/2012 |
from: |
Karanataka India |
|
|
|
|
|
LDAP paged result control |
I have a requirement the i need to fetch all the records from AD even if it is more than 1000 entries. I tried using PagedResult control (from net) it works fine for filter which has less than 1000 entries. But if the filter fetches more than 1000 (that is needed)
(JAVA) result is namingEnumeration
results.hasmore loop returns false and not going in to the loop.
What would be the reason it is failing?
Very urgent.Please help me in this regard.
Using the same code as above. |
|
|
|
|
|
|
krithiga member offline |
|
posts: |
|
joined: |
05/03/2012 |
from: |
Karanataka India |
|
|
|
|
|
LDAP paged result control |
I have a requirement the i need to fetch all the records from AD even if it is more than 1000 entries. I tried using PagedResult control (from net) it works fine for filter which has less than 1000 entries. But if the filter fetches more than 1000 (that is needed)
(JAVA) result is namingEnumeration
results.hasmore loop returns false and not going in to the loop.
What would be the reason it is failing?
Very urgent.Please help me in this regard.
Using the same code as above. |
|
|
|
|
|
|