1 /*
   2  * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.ldap;
  27 
  28 import java.util.Vector;
  29 import java.util.EventObject;
  30 
  31 import javax.naming.event.NamingEvent;
  32 import javax.naming.event.NamingExceptionEvent;
  33 import javax.naming.event.NamingListener;
  34 import javax.naming.ldap.UnsolicitedNotificationEvent;
  35 import javax.naming.ldap.UnsolicitedNotificationListener;
  36 
  37 /**
  38  * Package private class used by EventSupport to dispatch events.
  39  * This class implements an event queue, and a dispatcher thread that
  40  * dequeues and dispatches events from the queue.
  41  *
  42  * Pieces stolen from sun.misc.Queue.
  43  *
  44  * @author      Bill Shannon (from javax.mail.event)
  45  * @author      Rosanna Lee (modified for JNDI-related events)
  46  */
  47 final class EventQueue implements Runnable {
  48     final static private boolean debug = false;
  49 
  50     private static class QueueElement {
  51         QueueElement next = null;
  52         QueueElement prev = null;
  53         EventObject event = null;
  54         Vector<NamingListener> vector = null;
  55 
  56         QueueElement(EventObject event, Vector<NamingListener> vector) {
  57             this.event = event;
  58             this.vector = vector;
  59         }
  60     }
  61 
  62     private QueueElement head = null;
  63     private QueueElement tail = null;
  64     private Thread qThread;
  65 
  66     // package private
  67     EventQueue() {
  68         qThread = Obj.helper.createThread(this);
  69         qThread.setDaemon(true);  // not a user thread
  70         qThread.start();
  71     }
  72 
  73     // package private;
  74     /**
  75      * Enqueue an event.
  76      * @param event Either a {@code NamingExceptionEvent} or a subclass
  77      *        of {@code NamingEvent} or
  78      *        {@code UnsolicitedNotificationEvent}.
  79      * If it is a subclass of {@code NamingEvent}, all listeners must implement
  80      * the corresponding subinterface of {@code NamingListener}.
  81      * For example, for a {@code ObjectAddedEvent}, all listeners <em>must</em>
  82      * implement the {@code ObjectAddedListener} interface.
  83      * <em>The current implementation does not check this before dispatching
  84      * the event.</em>
  85      * If the event is a {@code NamingExceptionEvent}, then all listeners
  86      * are notified.
  87      * @param vector List of NamingListeners that will be notified of event.
  88      */
  89     synchronized void enqueue(EventObject event, Vector<NamingListener> vector) {
  90         QueueElement newElt = new QueueElement(event, vector);
  91 
  92         if (head == null) {
  93             head = newElt;
  94             tail = newElt;
  95         } else {
  96             newElt.next = head;
  97             head.prev = newElt;
  98             head = newElt;
  99         }
 100         notify();
 101     }
 102 
 103     /**
 104      * Dequeue the oldest object on the queue.
 105      * Used only by the run() method.
 106      *
 107      * @return    the oldest object on the queue.
 108      * @exception java.lang.InterruptedException if any thread has
 109      *              interrupted this thread.
 110      */
 111     private synchronized QueueElement dequeue()
 112                                 throws InterruptedException {
 113         while (tail == null)
 114             wait();
 115         QueueElement elt = tail;
 116         tail = elt.prev;
 117         if (tail == null) {
 118             head = null;
 119         } else {
 120             tail.next = null;
 121         }
 122         elt.prev = elt.next = null;
 123         return elt;
 124     }
 125 
 126     /**
 127      * Pull events off the queue and dispatch them.
 128      */
 129     public void run() {
 130         QueueElement qe;
 131 
 132         try {
 133             while ((qe = dequeue()) != null) {
 134                 EventObject e = qe.event;
 135                 Vector<NamingListener> v = qe.vector;
 136 
 137                 for (int i = 0; i < v.size(); i++) {
 138 
 139                     // Dispatch to corresponding NamingListener
 140                     // The listener should only be getting the event that
 141                     // it is interested in. (No need to check mask or
 142                     // instanceof subinterfaces.)
 143                     // It is the responsibility of the enqueuer to
 144                     // only enqueue events with listeners of the correct type.
 145 
 146                     if (e instanceof NamingEvent) {
 147                         ((NamingEvent)e).dispatch(v.elementAt(i));
 148 
 149                     // An exception occurred: if notify all naming listeners
 150                     } else if (e instanceof NamingExceptionEvent) {
 151                         ((NamingExceptionEvent)e).dispatch(v.elementAt(i));
 152                     } else if (e instanceof UnsolicitedNotificationEvent) {
 153                         ((UnsolicitedNotificationEvent)e).dispatch(
 154                             (UnsolicitedNotificationListener)v.elementAt(i));
 155                     }
 156                 }
 157 
 158                 qe = null; e = null; v = null;
 159             }
 160         } catch (InterruptedException e) {
 161             // just die
 162         }
 163     }
 164 
 165     // package private; used by EventSupport;
 166     /**
 167      * Stop the dispatcher so we can be destroyed.
 168      */
 169     void stop() {
 170         if (debug) System.err.println("EventQueue stopping");
 171         if (qThread != null) {
 172             qThread.interrupt();        // kill our thread
 173             qThread = null;
 174         }
 175     }
 176 }