Author |
Topic: Virtual List View (VLV) Control -- Code Example |
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
Virtual List View (VLV) Control -- Code Example |
Virtual List View (VLV) Control
The VLV Control allows a client to specify that the server return a contiguous subset of the search result set. This subset is specified in terms of offsets into the ordered list, or in terms of a greater than or equal comparison value.
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:
VLVControl ::= SEQUENCE {
controlType 2.16.840.1.113730.3.4.9,
criticality BOOLEAN DEFAULT FALSE,
controlValue VirtualListViewRequest
}
The VirtualListViewRequest is an OCTET STRING wrapping the BER-encoded version of the following SEQUENCE:
VirtualListViewRequest ::= SEQUENCE {
beforeCount INTEGER (0..maxInt),
afterCount INTEGER (0..maxInt),
target CHOICE {
byOffset [0] SEQUENCE {
offset INTEGER (1 .. maxInt),
contentCount INTEGER (0 .. maxInt)
},
greaterThanOrEqual [1] AssertionValue
},
contextID OCTET STRING OPTIONAL }
beforeCount indicates how many entries before the target entry the client wants the server to send. afterCount indicates the number of entries after the target entry the client wants the server to send. offset and contentCount identify the target entry. greaterThanOrEqual is a matching rule assertion value. The assertion value is encoded according to the ORDERING matching rule for the attributeDescription in the sort control [SSS]. If present, the value supplied in greaterThanOrEqual is used to determine the target entry by comparison with the values of the attribute specified as the primary sort key. The first list entry who's value is no less than (less than or equal to when the sort order is reversed) the supplied value is the target entry. contextID contains the value of the most recently received contextID field from a VirtualListViewResponse control for the same list view. If the contextID is not known because no contextID has been sent by the server in a VirtualListViewResponse control, it SHALL be omitted. If the server receives a contextID that is invalid, it SHALL fail the search operation and indicate the failure with a protocolError (3) value in the virtualListViewResult field of the VirtualListViewResponse. The contextID provides state information between the client and server. This state information is used by the server to ensure continuity contiguous virtual list requests. When a server receives a VirtualListViewRequest control that includes a contextID, it SHALL determine whether the client has sent a contiguous virtual list request and SHALL provide contiguous entries if possible. If a valid contextID is sent, and the server is unable to determine whether contiguous data is requested, or is unable to provide requested contiguous data, it SHALL fail the search operation and indicate the failure with an unwillingToPerform (53) value in the virtualListViewResult field of the VirtualListViewResponse. contextID values have no validity outside the connection and query with which they were received. A client MUST NOT submit a contextID which it received from a different connection, a different query, or a different server.
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
A code example of Proxy Virtual List View Control JNDI Client |
(Note: JNDI Boost package is required to run this code)
/**
*
* VLVJndiClient.java
* Sample code to demostrate how Virtual List View (VLV) Control works.
* Note:
* 1) Note: JNDI Boost package is required for this example to run.
* 2) VLV Control MUST be used in conjunction with Sort Control.
* Otherwise, you will be braced by: [LDAP: error code 60 - VLV Control]
* 3) SunOne Directory Server supports VLV & Microsoft supports VLV since AD2003
*
*/
import java.util.Hashtable;
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import com.sun.jndi.ldap.ctl.VirtualListViewControl;
import com.sun.jndi.ldap.ctl.VirtualListViewResponseControl;
import com.sun.jndi.ldap.ctl.SortControl;
public class VLVJndiClient
{
static final String VLV_CONTROL_OID = "2.16.840.1.113730.3.4.9";
public static void main(String[] args) throws IOException
{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://myserver.mydomain.com:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "mybinddn");
env.put(Context.SECURITY_CREDENTIALS, "mypassword");
try {
/* Create initial context with no connection request controls */
LdapContext ctx = new InitialLdapContext(env, null);
/* Query the server to see if the VLV Control is supported */
if (!isVLVControlSupported(ctx)){
System.out.println(
"The server does not support Virtual List View (VLV) Control.");
System.exit(1);
}
/* Sort Control is required for VLV to work */
SortControl sctl = new SortControl(
new String[]{"cn"}, // sort by cn
Control.CRITICAL
);
/* VLV that returns the first 20 answers */
VirtualListViewControl vctl =
new VirtualListViewControl(1, 0, 0, 19, Control.CRITICAL);
/* Set context's request controls */
ctx.setRequestControls(new Control[]{sctl, vctl});
/* Perform search */
NamingEnumeration answer =
ctx.search("ou=people,dc=com", "(objectclass=*)", null);
/* Enumerate search results */
while (answer.hasMore()) {
SearchResult si = (SearchResult)answer.next();
System.out.println(si.getName());
}
/* examine the response controls (if any) */
printControls(ctx.getResponseControls());
ctx.close();
} catch (NamingException e) {
e.printStackTrace();
}
}
static void printControls(Control[] controls)
{
if(controls == null){
System.out.println("No response controls");
return;
}
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());
} else {
System.out.println("Sorted-View did not complete successfully: "
+ vlv.getResultCode());
}
} else {
System.out.println("Received control: "+ controls[j].getID());
}
}
}
/**
* Is VLV Control supported?
*
* Query the rootDSE object to find out if VLV Control
* is supported.
*/
static boolean isVLVControlSupported(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(VLV_CONTROL_OID))
return true;
}
}
}
return false;
}
}
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
Who supports VLV? |
The above code has been tested working fine against:
1) SunOne Directory Server 5.2, 6.0 2) Fedora Directory Server 1.2.0 3) Active Directory Server AD2003, AD2008
|
|
|
|
|
|
|
SteveHB member offline |
|
posts: |
113 |
joined: |
05/31/2006 |
from: |
Mountain View, CA |
|
|
|
|
|
javax.naming.NamingException: [LDAP: error code 60 - VLV Control] |
Virtual List View (VLV) Control must be used in conjunction with Server-Side Sort (SSS) Control (click here to see why). Otherwise, errors similar to the followings are thrown:
javax.naming.NamingException: [LDAP: error code 60 - VLV Control]; remaining name 'ou=people,dc=com' at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3107) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2951) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2758) at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1812) at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1735) 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)
|
|
|
|
|
|
|
eightmd member offline |
|
posts: |
3 |
joined: |
10/18/2016 |
from: |
San Diego, CA |
|
|
|
|
|
Can not get the code example to work |
I know this is an old post but I'm having trouble getting the VLV control to work. I'm using ApacheDS and talking to it using Java JNDI just like the example code. Every time I run a search it returns all entries not just a subset. I have 10 users and I always get all 10 back in the results. I also get a SortResponseControl back and never a VirtualListViewResponseControl back. I took the example code and just changed the connection information and search criteria and I still get the same problem.
Some of the parameters I've tried for the VirtualListViewControl are:
new VirtualListViewControl(1, 0, 0, 19, Control.CRITICAL); // original - gets all new VirtualListViewControl(1, 10, 1, 2, Control.CRITICAL); // target offset -gets all new VirtualListViewControl(20, 3, Control.CRITICAL); // target percentage - gets all new VirtualListViewControl("Tryit4", 3, Control.CRITICAL); // target value, view size - gets all new VirtualListViewControl("Tryit4", 2, 1, Control.CRITICAL); // target value, before count, after count
I must be doing something wrong but I can't see what it is. Any help would be appreciated. Thanks
|
|
|
|
|
|
|
eightmd member offline |
|
posts: |
3 |
joined: |
10/18/2016 |
from: |
San Diego, CA |
|
|
|
|
|
Can not get the code example to work |
Sorry it posted twice. |
|
|
|
|
|
|
eightmd member offline |
|
posts: |
3 |
joined: |
10/18/2016 |
from: |
San Diego, CA |
|
|
|
|
|
|
I guess no one reads this forum any more, but if anyone does you can search this title on StackOverflow and I'll answer my own question over there. |
|
|
|
|
|
|
|