/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://oss.oracle.com/licenses/CDDL+GPL-1.1
* or LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.mail;
import java.util.EventListener;
import java.util.Vector;
import java.util.Queue;
import java.util.WeakHashMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Executor;
import javax.mail.event.MailEvent;
Package private class used by Store & Folder to dispatch events.
This class implements an event queue, and a dispatcher thread that
dequeues and dispatches events from the queue.
Author: Bill Shannon
/**
* Package private class used by Store & Folder to dispatch events.
* This class implements an event queue, and a dispatcher thread that
* dequeues and dispatches events from the queue.
*
* @author Bill Shannon
*/
class EventQueue implements Runnable {
private volatile BlockingQueue<QueueElement> q;
private Executor executor;
private static WeakHashMap<ClassLoader,EventQueue> appq;
A special event that causes the queue processing task to terminate.
/**
* A special event that causes the queue processing task to terminate.
*/
static class TerminatorEvent extends MailEvent {
private static final long serialVersionUID = -2481895000841664111L;
TerminatorEvent() {
super(new Object());
}
@Override
public void dispatch(Object listener) {
// Kill the event dispatching thread.
Thread.currentThread().interrupt();
}
}
A "struct" to put on the queue.
/**
* A "struct" to put on the queue.
*/
static class QueueElement {
MailEvent event = null;
Vector<? extends EventListener> vector = null;
QueueElement(MailEvent event, Vector<? extends EventListener> vector) {
this.event = event;
this.vector = vector;
}
}
Construct an EventQueue using the specified Executor.
If the Executor is null, threads will be created as needed.
/**
* Construct an EventQueue using the specified Executor.
* If the Executor is null, threads will be created as needed.
*/
EventQueue(Executor ex) {
this.executor = ex;
}
Enqueue an event.
/**
* Enqueue an event.
*/
synchronized void enqueue(MailEvent event,
Vector<? extends EventListener> vector) {
// if this is the first event, create the queue and start the event task
if (q == null) {
q = new LinkedBlockingQueue<>();
if (executor != null) {
executor.execute(this);
} else {
Thread qThread = new Thread(this, "JavaMail-EventQueue");
qThread.setDaemon(true); // not a user thread
qThread.start();
}
}
q.add(new QueueElement(event, vector));
}
Terminate the task running the queue, but only if there is a queue.
/**
* Terminate the task running the queue, but only if there is a queue.
*/
synchronized void terminateQueue() {
if (q != null) {
Vector<EventListener> dummyListeners = new Vector<>();
dummyListeners.setSize(1); // need atleast one listener
q.add(new QueueElement(new TerminatorEvent(), dummyListeners));
q = null;
}
}
Create (if necessary) an application-scoped event queue.
Application scoping is based on the thread's context class loader.
/**
* Create (if necessary) an application-scoped event queue.
* Application scoping is based on the thread's context class loader.
*/
static synchronized EventQueue getApplicationEventQueue(Executor ex) {
ClassLoader cl = Session.getContextClassLoader();
if (appq == null)
appq = new WeakHashMap<>();
EventQueue q = appq.get(cl);
if (q == null) {
q = new EventQueue(ex);
appq.put(cl, q);
}
return q;
}
Pull events off the queue and dispatch them.
/**
* Pull events off the queue and dispatch them.
*/
@Override
public void run() {
BlockingQueue<QueueElement> bq = q;
if (bq == null)
return;
try {
loop:
for (;;) {
// block until an item is available
QueueElement qe = bq.take();
MailEvent e = qe.event;
Vector<? extends EventListener> v = qe.vector;
for (int i = 0; i < v.size(); i++)
try {
e.dispatch(v.elementAt(i));
} catch (Throwable t) {
if (t instanceof InterruptedException)
break loop;
// ignore anything else thrown by the listener
}
qe = null; e = null; v = null;
}
} catch (InterruptedException e) {
// just die
}
}
}