1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 //
21 // This source code implements specifications defined by the Java
22 // Community Process. In order to remain compliant with the specification
23 // DO NOT add / change / or delete method signatures!
24 //
25 package javax.mail;
26
27 import java.util.LinkedList;
28 import java.util.List;
29
30 import javax.mail.event.MailEvent;
31
32 /**
33 * This is an event queue to dispatch javamail events on separate threads
34 * from the main thread. EventQueues are created by javamail Services
35 * (Transport and Store instances), as well as Folders created from Store
36 * instances. Each entity will have its own private EventQueue instance, but
37 * will delay creating it until it has an event to dispatch to a real listener.
38 *
39 * NOTE: It would be nice to use the concurrency support in Java 5 to
40 * manage the queue, but this code needs to run on Java 1.4 still. We also
41 * don't want to have dependencies on other packages with this, so no
42 * outside concurrency packages can be used either.
43 * @version $Rev: 582842 $ $Date: 2007-10-08 11:13:51 -0400 (Mon, 08 Oct 2007) $
44 */
45 class EventQueue implements Runnable {
46 /**
47 * The dispatch thread that handles notification events.
48 */
49 protected Thread dispatchThread;
50
51 /**
52 * The dispatching queue for events.
53 */
54 protected List eventQueue = new LinkedList();
55
56 /**
57 * Create a new EventQueue, including starting the new thread.
58 */
59 public EventQueue() {
60 dispatchThread = new Thread(this, "JavaMail-EventQueue");
61 dispatchThread.setDaemon(true); // this is a background server thread.
62 // start the thread up
63 dispatchThread.start();
64 }
65
66 /**
67 * When an object implementing interface <code>Runnable</code> is used
68 * to create a thread, starting the thread causes the object's
69 * <code>run</code> method to be called in that separately executing
70 * thread.
71 * <p>
72 * The general contract of the method <code>run</code> is that it may
73 * take any action whatsoever.
74 *
75 * @see java.lang.Thread#run()
76 */
77 public void run() {
78 try {
79 while (true) {
80 // get the next event
81 PendingEvent p = dequeueEvent();
82 // an empty event on the queue means time to shut things down.
83 if (p.event == null) {
84 return;
85 }
86
87 // and tap the listeners on the shoulder.
88 dispatchEvent(p.event, p.listeners);
89 }
90 } catch (InterruptedException e) {
91 // been told to stop, so we stop
92 }
93 }
94
95
96 /**
97 * Stop the EventQueue. This will terminate the dispatcher thread as soon
98 * as it can, so there may be undispatched events in the queue that will
99 * not get dispatched.
100 */
101 public synchronized void stop() {
102 // if the thread has not been stopped yet, interrupt it
103 // and clear the reference.
104 if (dispatchThread != null) {
105 // push a dummy marker on to the event queue
106 // to force the dispatch thread to wake up.
107 queueEvent(null, null);
108 dispatchThread = null;
109 }
110 }
111
112 /**
113 * Add a new event to the queue.
114 *
115 * @param event The event to dispatch.
116 * @param listeners The List of listeners to dispatch this to. This is assumed to be a
117 * static snapshot of the listeners that will not change between the time
118 * the event is queued and the dispatcher thread makes the calls to the
119 * handlers.
120 */
121 public synchronized void queueEvent(MailEvent event, List listeners) {
122 // add an element to the list, then notify the processing thread.
123 // Note that we make a copy of the listeners list. This ensures
124 // we're going to dispatch this to the snapshot of the listeners
125 PendingEvent p = new PendingEvent(event, listeners);
126 eventQueue.add(p);
127 // wake up the dispatch thread
128 notify();
129 }
130
131 /**
132 * Remove the next event from the message queue.
133 *
134 * @return The PendingEvent item from the queue.
135 */
136 protected synchronized PendingEvent dequeueEvent() throws InterruptedException {
137 // a little spin loop to wait for an event
138 while (eventQueue.isEmpty()) {
139 wait();
140 }
141
142 // just remove the first element of this
143 return (PendingEvent)eventQueue.remove(0);
144 }
145
146
147 /**
148 * Dispatch an event to a list of listeners. Any exceptions thrown by
149 * the listeners will be swallowed.
150 *
151 * @param event The event to dispatch.
152 * @param listeners The list of listeners this gets dispatched to.
153 */
154 protected void dispatchEvent(MailEvent event, List listeners) {
155 // iterate through the listeners list calling the handlers.
156 for (int i = 0; i < listeners.size(); i++) {
157 try {
158 event.dispatch(listeners.get(i));
159 } catch (Throwable e) {
160 // just eat these
161 }
162 }
163 }
164
165
166 /**
167 * Small helper class to give a single reference handle for a pending event.
168 */
169 class PendingEvent {
170 // the event we're broadcasting
171 MailEvent event;
172 // the list of listeners we send this to.
173 List listeners;
174
175 PendingEvent(MailEvent event, List listeners) {
176 this.event = event;
177 this.listeners = listeners;
178 }
179 }
180 }