View Javadoc

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 }