Add support for multiple VLV search contexts per connection for OpenLDAP HEAD (2.4)¶
Description¶
This patch add the capacity to support multiple VLV searches per connection. By default, OpenLDAP
Submit as ITS#6686
Usage¶
Instantiate a JNDI connection and multiple searches. This is a sample but this will be fully functional with your own code.
package org.linid.server.test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.SortControl;
import javax.naming.ldap.SortResponseControl;
import junit.framework.TestCase;
import com.sun.jndi.ldap.ctl.VirtualListViewControl;
import com.sun.jndi.ldap.ctl.VirtualListViewResponseControl;
public class TestVLV extends TestCase {
public static final String VLV_CONTROL_OID = "2.16.840.1.113730.3.4.9";
private LdapContext ldapCtx;
private Properties connProps;
public TestVLV() {
connProps = new Properties();
}
public void setUp() {
try {
connProps.load(new FileInputStream("ldap.properties"));
ldapCtx = new InitialLdapContext(connProps, (ldapCtx != null ? ldapCtx.getConnectControls(): null));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void testSearch() throws NamingException, IOException {
/* Query the server to see if the VLV Control is supported */
byte[] contextId = search(null, 100);
while(contextId != null) {
contextId = search(contextId, 100);
}
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ldapCtx.close();
}
private static int offset = 1;
private byte[] search(byte[] contextId, int maxsize) {
/* Sort Control is required for VLV to work */
try {
SortControl sctl = new SortControl(new String[] { "cn" },
Control.CRITICAL);
/* VLV that returns the first 20 answers */
VirtualListViewControl vctl = new VirtualListViewControl(
offset, 0, 0, maxsize-1, Control.CRITICAL);
offset += maxsize;
vctl.setContextID(contextId);
/* Set context's request controls */
ldapCtx.setRequestControls(new Control[] { sctl,
vctl });
SearchControls scs = new SearchControls();
// scs.setCountLimit(0);
scs.setDerefLinkFlag(true);
scs.setReturningAttributes(new String[] { "cn",
"sn", "givenName" });
scs.setReturningObjFlag(true);
scs.setCountLimit(1000);
scs.setSearchScope(SearchControls.SUBTREE_SCOPE);
// scs.setTimeLimit(0);
NamingEnumeration<?> ne = ldapCtx.search("",
"objectClass=person", scs);
int count = 0;
while (ne.hasMore()) {
System.out.println(((SearchResult) ne.nextElement())
.getNameInNamespace());
count ++;
}
if(count != maxsize) {
return null;
}
Control[] controls = ldapCtx.getResponseControls();
if (controls == null) {
System.out.println("No response controls");
} else {
for (int j = 0; j < controls.length; j++) {
if (controls[j] instanceof SortResponseControl) {
SortResponseControl src = (SortResponseControl) controls[j];
if (src.isSorted()) {
System.out
.println("Sorted-Search completed successfully");
} else {
System.out
.println("Sorted-Search did not complete successfully: error ("
+ src.getResultCode()
+ ") on attribute '"
+ src.getAttributeID()
+ "'");
}
} else if (controls[j] instanceof VirtualListViewResponseControl) {
VirtualListViewResponseControl vlv = (VirtualListViewResponseControl) controls[j];
if (vlv.getResultCode() == 0) {
System.out
.println("Sorted-View completed successfully");
System.out.println("TargetOffset: "
+ vlv.getTargetOffset());
System.out.println("ListSize: "
+ vlv.getListSize());
return vlv.getContextID();
} else {
System.out
.println("Sorted-View did not complete successfully: "
+ vlv.getResultCode());
}
} else {
System.out.println("Received control: "
+ controls[j].getID());
}
}
}
return null;
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* Is VLV Control supported?
*
* Query the rootDSE object to find out if VLV Control is supported.
*/
private boolean isVLVControlSupported() throws NamingException {
SearchControls ctl = new SearchControls();
ctl.setReturningAttributes(new String[] { "supportedControl" });
ctl.setSearchScope(SearchControls.OBJECT_SCOPE);
/* search for the rootDSE object */
NamingEnumeration<?> results = ldapCtx.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(VLV_CONTROL_OID))
return true;
}
}
}
return false;
}
}
Applying this patch¶
Download the OpenLDAP 2.3 branch, download the patch and apply it :
patch -p0 < fix-sssvlv-multiple-request-by-conn.patch