| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package com.sun.jndi.ldap;  | 
 | 
 | 
 | 
import javax.naming.*;  | 
 | 
import javax.naming.directory.*;  | 
 | 
import javax.naming.event.*;  | 
 | 
import javax.naming.ldap.*;  | 
 | 
import javax.naming.ldap.LdapName;  | 
 | 
 | 
 | 
import java.util.Vector;  | 
 | 
import com.sun.jndi.toolkit.ctx.Continuation;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
  */  | 
 | 
final class NamingEventNotifier implements Runnable { | 
 | 
    private final static boolean debug = false;  | 
 | 
 | 
 | 
    private Vector<NamingListener> namingListeners;  | 
 | 
    private Thread worker;  | 
 | 
    private LdapCtx context;  | 
 | 
    private EventContext eventSrc;  | 
 | 
    private EventSupport support;  | 
 | 
    private NamingEnumeration<SearchResult> results;  | 
 | 
 | 
 | 
      | 
 | 
    NotifierArgs info;  | 
 | 
 | 
 | 
    NamingEventNotifier(EventSupport support, LdapCtx ctx, NotifierArgs info,  | 
 | 
        NamingListener firstListener) throws NamingException { | 
 | 
        this.info = info;  | 
 | 
        this.support = support;  | 
 | 
 | 
 | 
        Control psearch;  | 
 | 
        try { | 
 | 
            psearch = new PersistentSearchControl(  | 
 | 
                info.mask,  | 
 | 
                true ,  | 
 | 
                true ,  | 
 | 
                Control.CRITICAL);  | 
 | 
        } catch (java.io.IOException e) { | 
 | 
            NamingException ne = new NamingException(  | 
 | 
                "Problem creating persistent search control");  | 
 | 
            ne.setRootCause(e);  | 
 | 
            throw ne;  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        context = (LdapCtx)ctx.newInstance(new Control[]{psearch}); | 
 | 
        eventSrc = ctx;  | 
 | 
 | 
 | 
        namingListeners = new Vector<>();  | 
 | 
        namingListeners.addElement(firstListener);  | 
 | 
 | 
 | 
        worker = Obj.helper.createThread(this);  | 
 | 
        worker.setDaemon(true);    | 
 | 
        worker.start();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    void addNamingListener(NamingListener l) { | 
 | 
        namingListeners.addElement(l);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    void removeNamingListener(NamingListener l) { | 
 | 
        namingListeners.removeElement(l);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    boolean hasNamingListeners() { | 
 | 
        return namingListeners.size() > 0;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void run() { | 
 | 
        try { | 
 | 
            Continuation cont = new Continuation();  | 
 | 
            cont.setError(this, info.name);  | 
 | 
            Name nm = (info.name == null || info.name.equals("")) ? | 
 | 
                new CompositeName() : new CompositeName().add(info.name);  | 
 | 
 | 
 | 
            results = context.searchAux(nm, info.filter, info.controls,  | 
 | 
                true, false, cont);  | 
 | 
 | 
 | 
            // Change root of search results so that it will generate  | 
 | 
            // names relative to the event context instead of that  | 
 | 
              | 
 | 
            ((LdapSearchEnumeration)(NamingEnumeration)results)  | 
 | 
                    .setStartName(context.currentParsedDN);  | 
 | 
 | 
 | 
            SearchResult si;  | 
 | 
            Control[] respctls;  | 
 | 
            EntryChangeResponseControl ec;  | 
 | 
            long changeNum;  | 
 | 
 | 
 | 
            while (results.hasMore()) { | 
 | 
                si = results.next();  | 
 | 
                respctls = (si instanceof HasControls) ?  | 
 | 
                    ((HasControls) si).getControls() : null;  | 
 | 
 | 
 | 
                if (debug) { | 
 | 
                    System.err.println("notifier: " + si); | 
 | 
                    System.err.println("respCtls: " + respctls); | 
 | 
                }  | 
 | 
 | 
 | 
                  | 
 | 
                if (respctls != null) { | 
 | 
                    for (int i = 0; i < respctls.length; i++) { | 
 | 
                        // %%% Should be checking OID instead of class  | 
 | 
                          | 
 | 
                        if (respctls[i] instanceof EntryChangeResponseControl) { | 
 | 
                            ec = (EntryChangeResponseControl)respctls[i];  | 
 | 
                            changeNum = ec.getChangeNumber();  | 
 | 
                            switch (ec.getChangeType()) { | 
 | 
                            case EntryChangeResponseControl.ADD:  | 
 | 
                                fireObjectAdded(si, changeNum);  | 
 | 
                                break;  | 
 | 
                            case EntryChangeResponseControl.DELETE:  | 
 | 
                                fireObjectRemoved(si, changeNum);  | 
 | 
                                break;  | 
 | 
                            case EntryChangeResponseControl.MODIFY:  | 
 | 
                                fireObjectChanged(si, changeNum);  | 
 | 
                                break;  | 
 | 
                            case EntryChangeResponseControl.RENAME:  | 
 | 
                                fireObjectRenamed(si, ec.getPreviousDN(),  | 
 | 
                                    changeNum);  | 
 | 
                                break;  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } catch (InterruptedNamingException e) { | 
 | 
            if (debug) System.err.println("NamingEventNotifier Interrupted"); | 
 | 
        } catch (NamingException e) { | 
 | 
              | 
 | 
            fireNamingException(e);  | 
 | 
 | 
 | 
              | 
 | 
            support.removeDeadNotifier(info);  | 
 | 
        } finally { | 
 | 
            cleanup();  | 
 | 
        }  | 
 | 
        if (debug) System.err.println("NamingEventNotifier finished"); | 
 | 
    }  | 
 | 
 | 
 | 
    private void cleanup() { | 
 | 
        if (debug) System.err.println("NamingEventNotifier cleanup"); | 
 | 
 | 
 | 
        try { | 
 | 
            if (results != null) { | 
 | 
                if (debug) System.err.println("NamingEventNotifier enum closing"); | 
 | 
                results.close();   | 
 | 
                results = null;  | 
 | 
            }  | 
 | 
            if (context != null) { | 
 | 
                if (debug) System.err.println("NamingEventNotifier ctx closing"); | 
 | 
                context.close();  | 
 | 
                context = null;  | 
 | 
            }  | 
 | 
        } catch (NamingException e) {} | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    void stop() { | 
 | 
        if (debug) System.err.println("NamingEventNotifier being stopping"); | 
 | 
        if (worker != null) { | 
 | 
            worker.interrupt();   | 
 | 
            worker = null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void fireObjectAdded(Binding newBd, long changeID) { | 
 | 
        if (namingListeners == null || namingListeners.size() == 0)  | 
 | 
            return;  | 
 | 
 | 
 | 
        NamingEvent e = new NamingEvent(eventSrc, NamingEvent.OBJECT_ADDED,  | 
 | 
            newBd, null, new Long(changeID));  | 
 | 
        support.queueEvent(e, namingListeners);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void fireObjectRemoved(Binding oldBd, long changeID) { | 
 | 
        if (namingListeners == null || namingListeners.size() == 0)  | 
 | 
            return;  | 
 | 
 | 
 | 
        NamingEvent e = new NamingEvent(eventSrc, NamingEvent.OBJECT_REMOVED,  | 
 | 
            null, oldBd, new Long(changeID));  | 
 | 
        support.queueEvent(e, namingListeners);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void fireObjectChanged(Binding newBd, long changeID) { | 
 | 
        if (namingListeners == null || namingListeners.size() == 0)  | 
 | 
            return;  | 
 | 
 | 
 | 
          | 
 | 
        Binding oldBd = new Binding(newBd.getName(), null, newBd.isRelative());  | 
 | 
 | 
 | 
        NamingEvent e = new NamingEvent(  | 
 | 
            eventSrc, NamingEvent.OBJECT_CHANGED, newBd, oldBd, new Long(changeID));  | 
 | 
        support.queueEvent(e, namingListeners);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void fireObjectRenamed(Binding newBd, String oldDN, long changeID) { | 
 | 
        if (namingListeners == null || namingListeners.size() == 0)  | 
 | 
            return;  | 
 | 
 | 
 | 
        Binding oldBd = null;  | 
 | 
        try { | 
 | 
            LdapName dn = new LdapName(oldDN);  | 
 | 
            if (dn.startsWith(context.currentParsedDN)) { | 
 | 
                String relDN = dn.getSuffix(context.currentParsedDN.size()).toString();  | 
 | 
                oldBd = new Binding(relDN, null);  | 
 | 
            }  | 
 | 
        } catch (NamingException e) {} | 
 | 
 | 
 | 
        if (oldBd == null) { | 
 | 
            oldBd = new Binding(oldDN, null, false /* not relative name */);  | 
 | 
        }  | 
 | 
 | 
 | 
        NamingEvent e = new NamingEvent(  | 
 | 
            eventSrc, NamingEvent.OBJECT_RENAMED, newBd, oldBd, new Long(changeID));  | 
 | 
        support.queueEvent(e, namingListeners);  | 
 | 
    }  | 
 | 
 | 
 | 
    private void fireNamingException(NamingException e) { | 
 | 
        if (namingListeners == null || namingListeners.size() == 0)  | 
 | 
            return;  | 
 | 
 | 
 | 
        NamingExceptionEvent evt = new NamingExceptionEvent(eventSrc, e);  | 
 | 
        support.queueEvent(evt, namingListeners);  | 
 | 
    }  | 
 | 
}  |