三种解决方法:第一种不好用,希望有高手回帖。第三种没测试,希望有心人帮测。
1、 batch size
Batch Size
When you invoke list(), listBindings(), or any of the search() methods,
the LDAP service provider interacts with the LDAP server to retrieve the
results and returns them in the form of a NamingEnumeration. The LDAP s
ervice provider can collect all the results before returning the NamingE
numeration, or it can return each result as the caller invokes NamingEnu
meration.next() or NamingEnumeration.nextElement(). You can control how
the LDAP service provider behaves in this respect by using the Context.B
ATCHSIZE ("java.naming.batchsize") environment property. This property c
ontains the string representation of a decimal integer. The LDAP service
provider uses its value to determine how many results to read from the
server before unblocking--this number of results is called the batch siz
e--and allowing the client program to get the results by using next() or
nextElement(). When the client program exhausts the batch, the LDAP ser
vice provider fetches another batch so that the client program can conti
nue with the enumeration. If the batch size is zero, then the service pr
ovider will block until all results have been read. If this property was
not set, then the default batch size is 1.
When you invoke search(), for example by using a batch size of n, the LD
AP provider will block until it reads n results from the server before r
eturning. So, setting the batch size to a smaller number allows the prog
ram to unblock sooner. However, some overhead attaches to processing eac
h batch. If you are expecting a large number of results, then you might
want to use a larger batch size to lower the number of context switches
between the provider and your code. On the other hand, having a large ba
tch also means that you need more memory to hold the results. These are
the trade-offs that you'll need to consider when choosing a batch size.
Here's an example that sets the batch size to 10.
// Set the batch size to 10
env.put("java.naming.batchsize", "10");
// Create the initial context
DirContext ctx = new InitialDirContext(env);
// Perform the list
NamingEnumeration answer = ctx.list("ou=People");
Relationship to SearchControls.setCountLimit()
Note that the Context.BATCHSIZE environment property does not in any way
affect how many results are returned or the order in which they are ret
urned. It is completely unrelated to SearchControls.setCountLimit().
经过实验,发现这种方法好象没用,不清楚为什么,等有空的时候需要研究一下。
2、paged search
A few other problems that developers come across are queries that return
either a large number of results, or query that returns a multi-valued
attribute that contains a large number of values.
Active Directory incorporates a number of controls, that are designed to
ensure optimim performance of the server and to mitigate denial of serv
ice attacks.
First of all paging. By default, Active Directory restricts the total nu
mber of results that are returned from a LDAP Search to 1000. While this
limit can be changed by modifying the LDAP Query policy, the recomended
approach is to use paged results. Note that this ample, which queries f
or all users that have a value for the mail attribute. uses a page size
of 10, not really an optimal use of either the server or of the network,
but merely just to demonstrate paging.
Also, the usual security comments apply, you shouldn't hardcode credenti
als in an application, authentication should either use Kerberos (JAAS &
GSSAPI) or if using simple authentication, secured using SSL or TLS, an
d and any sensitive information communicated between the client and the
server should also take place over SSL or TLS.
.
/**
* paged.java
* 5 July 2001
* Sample JNDI application that performs a paged search.
*
*/
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import com.sun.jndi.ldap.ctl.*;
class paged {
public static void main(String[] args) {
Hashtable env = new Hashtable();
String adminName = "CN=Administrator,CN=Users,DC=antipodes,DC=com";
String adminPassword = "XXXXXXXX";
String searchBase = "DC=antipodes,DC=com";
String searchFilter = "(&(objectClass=user)(mail=*))";
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFact
ory");
//set security credentials, note using simple cleartext
authentication
env.put(Context.SECURITY_AUTHENTICATION,"simple");
env.put(Context.SECURITY_PRINCIPAL,adminName);
env.put(Context.SECURITY_CREDENTIALS,adminPassword);
//connect to my domain controller
env.put(Context.PROVIDER_URL, "ldap://mydc.antipodes.com:389");
try {
// Create the initial directory context
LdapContext ctx = new InitialLdapContext(env,null);
// Create the search controls
SearchControls searchCtls = new SearchControls();
//Specify the attributes to return
String returnedAtts[]={"sn","givenName","mail"};
searchCtls.setReturningAttributes(returnedAtts);
//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
//Set the page size and initialize the cookie that we pass back
in su
bsequent pages
int pageSize = 10;
byte[] cookie = null;
//Request the paged results control
Control[] ctls = new Control[]{new
PagedResultsControl(pageSize)};
ctx.setRequestControls(ctls);
//initialize counter to total the results
int totalResults = 0;
// Search for objects using the filter
do {
NamingEnumeration results = ctx.search(searchBase,
searchFilter, sea
rchCtls);
// loop through the results in each page
while (results != null && results.hasMoreElements()) {
SearchResult sr = (SearchResult)results.next();
//print out the name
System.out.println("name: " + sr.getName());
//increment the counter
totalResults++;
}
// examine the response controls
cookie = parseControls(ctx.getResponseControls());
// pass the cookie back to the server for the next page
ctx.setRequestControls(new Control[]{new
PagedResultsControl(pageSize
, cookie, Control.CRITICAL) });
} while ((cookie != null) && (cookie.length != 0));
ctx.close();
System.out.println("Total entries: " + totalResults);
}
catch (NamingException e) {
System.err.println("Paged Search failed." + e);
}
catch (java.io.IOException e) {
System.err.println("Paged Search failed." + e);
}
}
static byte[] parseControls(Control[] controls) throws NamingException
{
byte[] cookie = null;
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc =
(PagedResultsResponseControl)con
trols[i];
cookie = prrc.getCookie();
System.out.println(">>Next Page \n");
}
}
}
return (cookie == null) ? new byte[0] : cookie;
}
}
经测试,这种方法可以解决问题
3、range search
Note that if we had requested a multi-valued attribute instead of the su
rname (sn), firstname (givenName) and e-mail (mail) attributes, and if t
hat multi-valued had more than 1000 values, then only the first 1000 val
ues would have been returned, irrespective of whether paged results had
ben used.
Range retrieval is more evident when retrieving the list of members from
a group. The list of members in a group is contained in the member attr
ibute. If there are more than 1000 values in the member attribute, then
you must use range retrieval to return all the members.
Information on range retrieval can be found at http://msdn.microsoft.com
/library/default.asp?url=/library/en-us/adsi/adsi/attribute_range_retrie
val.asp
The following JNDI sample illustrates the retrieval of members from a gr
oup, using range retrieval. In this case querying for the list of member
s of a group called "All Research" in the Active Directory.
/**
* range.java
* December 2004
* Sample JNDI application to demonstrate range retrieval
*
*/
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.ldap.*;
import javax.naming.directory.*;
import com.sun.jndi.ldap.ctl.*;
//if we were going to do this properly, should check that the server sup
ports
//the range retrieval control 1.2.840.113556.1.4.802 !
public class range {
public static void main (String[] args) {
Hashtable env = new Hashtable();
String adminName = "CN=Administrator,CN=Users,DC=ANTIPODES,DC=COM";
String adminPassword = "XXXXXX";
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFact
ory");
//set security credentials, note using simple cleartext
authentication
env.put(Context.SECURITY_AUTHENTICATION,"simple");
env.put(Context.SECURITY_PRINCIPAL,adminName);
env.put(Context.SECURITY_CREDENTIALS,adminPassword);
//connect to my domain controller
env.put(Context.PROVIDER_URL,"ldap://mydc.antipodes.com:389");
try {
// Create the initial directory context
LdapContext ctx = new InitialLdapContext(env,null);
// Create the search controls
SearchControls searchCtls = new SearchControls();
//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
//specify the LDAP search filter
String searchFilter = "(&(objectClass=group)(CN=All Research))";
//Specify the Base for the search
String searchBase = "DC=antipodes,DC=com";
//initialize counter to total the group members and range values
int totalResults = 0;
int Start = 0;
int Step = 10;
int Finish = 9;
boolean Finished = false;
String Range;
//loop through the query until we have all the results
while (!Finished) {
//Specify the attributes to return
Range = Start + "-" + Finish;
String returnedAtts[]={"member;Range=" + Range};
searchCtls.setReturningAttributes(returnedAtts);
//Search for objects using the filter
NamingEnumeration answer = ctx.search(searchBase,
searchFilter, sear
chCtls);
//Loop through the search results
while (answer.hasMoreElements()) {
SearchResult sr = (SearchResult)answer.next();
System.out.println(">>>" + sr.getName());
//Print out the members
Attributes attrs = sr.getAttributes();
if (attrs != null) {
try {
for (NamingEnumeration ae =
attrs.getAll();ae.hasMore();) {
Attribute attr = (Attribute)ae.next();
//check if we are finished
if (attr.getID().endsWith("*")) {
Finished=true;
}
System.out.println("Attribute: " +
attr.getID());
for (NamingEnumeration e =
attr.getAll();e.hasMore();totalResult
s++) {
System.out.println(" " + totalResults
+ ". " + e.next());
}
}
}
catch (NamingException e) {
System.err.println("Problem printing
attributes: " + e);
}
Start = Start + Step;
Finish = Finish + Step;
}
}
}
System.out.println("Total members: " + totalResults);
ctx.close();
}
catch (NamingException e) {
System.err.println("Problem searching directory: " + e);
}
}
}