/**
* A code example of Persistent Search Control JNDI Client
* Note: This example has been tested to work with SunOne Directory Server
* It doesn't work with Active Directory.
*/
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.event.*;
import javax.naming.ldap.*;
import java.util.Hashtable;
import java.io.*;
public class PersistentSearchControlJndiClient
{
static final String PERSISTENT_SEARCH_OID = "2.16.840.1.113730.3.4.3";
static final String QUIT_PROMPT = "\nEnter 'q' to quit: ";
public static void main(String[] args)
{
LdapContext rootContext;
EventDirContext eventContext;
//create initial context
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://myserevr.mycompany.com:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=directory manager");
env.put(Context.SECURITY_CREDENTIALS, "mypassword");
env.put(Context.BATCHSIZE, "1"); //return each change as it occurs
env.put("java.naming.ldap.derefAliases", "never");
try{
// creating the initial context performs the LDAP bind
rootContext = new InitialLdapContext(env, null);
// verify that persistent search is supported, exit if not supported
if (!isPersistentSearchSupported(rootContext)){
System.out.println(
"The LDAP Server does not support persistent search");
System.exit(1);
}
// do a look up of the search base to create an EventDirContext
// to which the search listener can be added.
eventContext = (EventDirContext)rootContext.lookup("dc=mydomain,dc=com");
// create a MyEventListener instance to listen for events
MyEventListener listener = new MyEventListener("mylistener");
// Set up the search constraints
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Add the naming listener to the searchBase context. The interface
// methods of the listener will be called in a separate thread when
// a relevant event occurs
eventContext.addNamingListener(
"", //use the eventContext object as the target
"(objectClass=*)", //filter, include all objects
constraints, //search the subtree below the eventContext
listener); //the listener object
// loop until the user enters a q to quit.
BufferedReader in
= new BufferedReader(new InputStreamReader(System.in));
try{
String input;
while (true){
System.out.print(QUIT_PROMPT);
input = in.readLine();
if ( input.startsWith("q") || input.startsWith("Q") )
break;
}
}
catch(IOException e)
{
System.out.println(e.getMessage());
}
// Not strictly necessary since the context is closed below
eventContext.removeNamingListener(listener);
// Close context when we're done
eventContext.close();
}
catch(AuthenticationException e)
{
System.out.println(e.getMessage());
}
catch(NamingException e)
{
System.out.println(e.getMessage());
}
}
/**
* isPersistentSearchSupported
*
* Query the rootDSE to find out if the persistent search control
* is supported.
*/
static boolean isPersistentSearchSupported(
LdapContext rootContext) throws NamingException
{
SearchResult rootDSE;
NamingEnumeration searchResults;
Attributes attrs;
NamingEnumeration attrEnum;
Attribute attr;
NamingEnumeration values;
String value;
String[] attrNames = {"supportedControl"};
SearchControls searchControls = new SearchControls();
searchControls.setCountLimit(0); //0 means no limit
searchControls.setReturningAttributes(attrNames);
searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
// search for the rootDSE object
searchResults =
rootContext.search("", "(objectClass=*)", searchControls);
while (searchResults.hasMore())
{
rootDSE = (SearchResult)searchResults.next();
attrs = rootDSE.getAttributes();
attrEnum = attrs.getAll();
while (attrEnum.hasMore())
{
attr = (Attribute)attrEnum.next();
values = attr.getAll();
while (values.hasMore())
{
value = (String) values.next();
if (value.equals(PERSISTENT_SEARCH_OID))
return true;
}
}
}
return false;
}
/**
* MyEventlistener class
* An instance of this class is registered with an EventDirContext object.
* The registered instance's NamespaceChangeListener interface methods are
* called when a pertinent event occurs.
*/
static class MyEventListener implements NamespaceChangeListener,
ObjectChangeListener
{
private String id;
public MyEventListener(String id)
{
this.id = id;
}
public void objectAdded(NamingEvent evt)
{
System.out.println(
"\n\n" + id + ">>> object added event. Object Name: " +
evt.getNewBinding().getName());
System.out.print(QUIT_PROMPT);
}
public void objectRemoved(NamingEvent evt)
{
System.out.println(
"\n\n" + id + ">>> object removed event. Object Name: " +
evt.getOldBinding().getName());
System.out.print(QUIT_PROMPT);
}
public void objectRenamed(NamingEvent evt)
{
System.out.println(
"\n\n" + id + ">>> object renamed event. New name: " +
evt.getNewBinding().getName() +
" Old name: " + evt.getOldBinding().getName());
System.out.print(QUIT_PROMPT);
}
public void objectChanged(NamingEvent evt)
{
System.out.println(
"\n\n" + id + ">>> object changed event. Object name: " +
evt.getNewBinding().getName());
System.out.print(QUIT_PROMPT);
}
public void namingExceptionThrown(NamingExceptionEvent evt)
{
System.out.println(
"\n\n" + id + ">>> Listener received a naming exception");
evt.getException().printStackTrace();
System.out.print(QUIT_PROMPT);
}
}
}