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 
QueueElement(EventObject event, Vector<NamingListener> vector)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
EventQueue()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 an {@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      */
enqueue(EventObject event, Vector<NamingListener> vector)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      */
dequeue()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      */
run()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      */
stop()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 }
177