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
26package com.sun.jndi.ldap;
27
28import java.util.Vector;
29import java.util.EventObject;
30
31import javax.naming.event.NamingEvent;
32import javax.naming.event.NamingExceptionEvent;
33import javax.naming.event.NamingListener;
34import javax.naming.ldap.UnsolicitedNotificationEvent;
35import 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 */
47final 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 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     */
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}
177