/*
* 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
*/
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.
*/
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.
*/
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.
*/
EventQueue(
Executor ex) {
this.
executor =
ex;
}
/**
* 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.
*/
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.
*/
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.
*/
@
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
}
}
}