LDAP: как вернуть более 1000 результатов (Java)
Я использую LDAP SDK с этого сайта: https://www.unboundid.com/products/ldap-sdk/. Я хотел бы сделать операцию поиска, которая возвращает много записей.
Согласно сайту часто задаваемых вопросов ( https://www.unboundid.com/products/ldap-sdk/docs/ldapsdk-faq.php) я должен использовать реализацию SearchResultListener.
Итак, вот что я сделал:
public class UpdateThread extends Thread implements SearchResultListener {
...
// create request
final SearchRequest request = new SearchRequest(this, instance.getBaseDN(),SearchScope.SUB, filter);
// Setting size limit of results.
request.setSizeLimit(2000);
...
// Get every result one by one.
@Override
public void searchEntryReturned(SearchResultEntry arg0) {
System.out.println("entry "+arg0.getDN());
}
Проблема в том, что searchEntryReturned возвращает максимум 1000 результатов. Даже если я установлю ограничение размера на "2000".
4 ответа
Хотя почти наверняка сервер применяет ограничение размера в 1000 записей, потенциально можно обойти это, выполнив запрос из нескольких частей.
Если сервер поддерживает использование простого элемента управления результатами поиска (как определено в RFC 2696 и поддерживается в SDK LDAP согласно https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/controls/SimplePagedResultsControl.html), затем вы можете использовать его для перебора результатов в "страницах", содержащих указанное количество записей.
Альтернативно, управление запросом представления виртуального списка (VLV) ( https://www.unboundid.com/products/ldap-sdk/docs/javadoc/index.html?com/unboundid/ldap/sdk/controls/VirtualListViewRequestControl.html) можно было бы использовать, но я бы, вероятно, рекомендовал бы только, если сервер не поддерживает простой элемент управления постраничными результатами, потому что элемент управления запросом VLV также требует сортировки результатов, и это, вероятно, либо требует специальной настройки на сервере, либо довольно дорого обработка, чтобы иметь возможность обслуживать запрос.
Довольно просто реализовать постраничный запрос LDAP, используя стандартную Java, с помощью добавления PagedResultsControl
к LdapContext
без использования стороннего API согласно ответу Нила выше.
Hashtable<String, Object> env = new Hashtable<String, Object>(11);
env
.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
/* Specify host and port to use for directory service */
env.put(Context.PROVIDER_URL,
"ldap://localhost:389/ou=People,o=JNDITutorial");
try {
LdapContext ctx = new InitialLdapContext(env, null);
// Activate paged results
int pageSize = 5;
byte[] cookie = null;
ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize,
Control.NONCRITICAL) });
int total;
do {
/* perform the search */
NamingEnumeration results = ctx.search("", "(objectclass=*)",
new SearchControls());
/* for each entry print out name + all attrs and values */
while (results != null && results.hasMore()) {
SearchResult entry = (SearchResult) results.next();
System.out.println(entry.getName());
}
// Examine the paged results control response
Control[] controls = ctx.getResponseControls();
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
total = prrc.getResultSize();
if (total != 0) {
System.out.println("***************** END-OF-PAGE "
+ "(total : " + total + ") *****************\n");
} else {
System.out.println("***************** END-OF-PAGE "
+ "(total: unknown) ***************\n");
}
cookie = prrc.getCookie();
}
}
} else {
System.out.println("No controls were sent from the server");
}
// Re-activate paged results
ctx.setRequestControls(new Control[] { new PagedResultsControl(
pageSize, cookie, Control.CRITICAL) });
} while (cookie != null);
ctx.close();
Пример скопирован отсюда.
Я решил как @PeterK, но с некоторыми изменениями
public List<MyUser> listUsers() {
LOG.info("listUsers() inicio");
List<MyUser> users = new ArrayList<MyUser>();
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CTX);
env.put(Context.PROVIDER_URL, 'ldap://192.168.10.10:389');
env.put(Context.SECURITY_AUTHENTICATION, CONNECTION_TYPE);
env.put(Context.SECURITY_PRINCIPAL, USER_ADMIN_PASSWORD);
env.put(Context.SECURITY_CREDENTIALS, USER_ADMIN);
try {
LdapContext ctx = new InitialLdapContext(env, null);
// Activate paged results
int pageSize = 1000;
byte[] cookie = null;
ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, Control.NONCRITICAL) });
int total;
do {
/* perform the search */
SearchControls sc = new SearchControls();
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filtro = "(&(sAMAccountName=*)&(objectClass=user))";
NamingEnumeration results = ctx.search(getBaseDn(ctx), filtro, sc);
/* for each entry */
while (results.hasMoreElements()) {
SearchResult result = (SearchResult) results.nextElement();
Attributes attributes = result.getAttributes();
//convert to MyUser class
MyUser user = toUser(attributes);
users.add(user);
}
// Examine the paged results control response
Control[] controls = ctx.getResponseControls();
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
total = prrc.getResultSize();
if (total != 0) {
System.out.println("***************** END-OF-PAGE " + "(total : " + total + ") *****************\n");
} else {
System.out.println("***************** END-OF-PAGE " + "(total: unknown) ***************\n");
}
cookie = prrc.getCookie();
}
}
} else {
System.out.println("No controls were sent from the server");
}
// Re-activate paged results
ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
} while (cookie != null);
ctx.close();
} catch (NamingException e) {
System.err.println("PagedSearch failed.");
e.printStackTrace();
} catch (IOException ie) {
System.err.println("PagedSearch failed.");
ie.printStackTrace();
} catch (Exception ie) {
System.err.println("PagedSearch failed.");
ie.printStackTrace();
}
LOG.info("listUsers() size = " + (users.size()));
LOG.info("listUsers() fim");
return users;
}
private MyUser toUser(Attributes attributes) throws NamingException {
if (attributes != null) {
String fullName = attributes.get("distinguishedName") != null ? attributes.get("distinguishedName").get().toString() : null;
String mail = attributes.get("mail") != null ? attributes.get("mail").get().toString() : null;
String userName = attributes.get("cn") != null ? attributes.get("cn").get().toString() : null;
String userPrincipalName = attributes.get("userPrincipalName") != null ? attributes.get("userPrincipalName").get().toString() : null;
if (userPrincipalName != null) {
String[] user = userPrincipalName.split("@");
if (user != null && user.length > 0) {
userName = user[0];
}
}
MyUser user = new MyUser();
user.setFullName(fullName);
user.setEmail(mail);
user.setName(userName);
user.setUserPrincipalName(userPrincipalName);
user.setRoles(getRolesUser(attributes));
return user;
}
return null;
}
Клиент LDAP устанавливает ограничение размера "запрошенный клиентом" 2000. Этот предел запрошенного клиента не может переопределить ограничения, установленные в конфигурации сервера. Независимо от того, каков размер запрошенного клиентом размера, ограничение размера сервера переопределяет его. Обратитесь к администратору сервера каталогов и попросите увеличить ограничение размера.