/*
* Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.awt.event;
import java.awt.ActiveEvent;
import java.awt.AWTEvent;
/**
* An event which executes the run()
method on a Runnable
*
when dispatched by the AWT event dispatcher thread. This class can
* be used as a reference implementation of ActiveEvent
rather
* than declaring a new class and defining dispatch()
.
*
* Instances of this class are placed on the EventQueue
by calls
* to invokeLater
and invokeAndWait
. Client code
* can use this fact to write replacement functions for invokeLater
*
and invokeAndWait
without writing special-case code
* in any AWTEventListener
objects.
*
* An unspecified behavior will be caused if the {@code id} parameter
* of any particular {@code InvocationEvent} instance is not
* in the range from {@code INVOCATION_FIRST} to {@code INVOCATION_LAST}.
*
* @author Fred Ecks
* @author David Mendenhall
*
* @see java.awt.ActiveEvent
* @see java.awt.EventQueue#invokeLater
* @see java.awt.EventQueue#invokeAndWait
* @see AWTEventListener
*
* @since 1.2
*/
public class InvocationEvent extends AWTEvent implements ActiveEvent {
/**
* Marks the first integer id for the range of invocation event ids.
*/
public static final int INVOCATION_FIRST = 1200;
/**
* The default id for all InvocationEvents.
*/
public static final int INVOCATION_DEFAULT = INVOCATION_FIRST;
/**
* Marks the last integer id for the range of invocation event ids.
*/
public static final int INVOCATION_LAST = INVOCATION_DEFAULT;
/**
* The Runnable whose run() method will be called.
*/
protected Runnable runnable;
/**
* The (potentially null) Object whose notifyAll() method will be called
* immediately after the Runnable.run() method has returned or thrown an exception.
*
* @see #isDispatched
*/
protected Object notifier;
/**
* Indicates whether the run()
method of the runnable
* was executed or not.
*
* @see #isDispatched
* @since 1.7
*/
private volatile boolean dispatched = false;
/**
* Set to true if dispatch() catches Throwable and stores it in the
* exception instance variable. If false, Throwables are propagated up
* to the EventDispatchThread's dispatch loop.
*/
protected boolean catchExceptions;
/**
* The (potentially null) Exception thrown during execution of the
* Runnable.run() method. This variable will also be null if a particular
* instance does not catch exceptions.
*/
private Exception exception = null;
/**
* The (potentially null) Throwable thrown during execution of the
* Runnable.run() method. This variable will also be null if a particular
* instance does not catch exceptions.
*/
private Throwable throwable = null;
/**
* The timestamp of when this event occurred.
*
* @serial
* @see #getWhen
*/
private long when;
/*
* JDK 1.1 serialVersionUID.
*/
private static final long serialVersionUID = 436056344909459450L;
/**
* Constructs an InvocationEvent
with the specified
* source which will execute the runnable's run
* method when dispatched.
*
This is a convenience constructor. An invocation of the form * InvocationEvent(source, runnable) * behaves in exactly the same way as the invocation of * {@link #InvocationEvent(Object, Runnable, Object, boolean) InvocationEvent}(source, runnable, null, false). *
This method throws an IllegalArgumentException
* if source
is null
.
*
* @param source The Object
that originated the event
* @param runnable The Runnable
whose run
* method will be executed
* @throws IllegalArgumentException if source
is null
*
* @see #getSource()
* @see #InvocationEvent(Object, Runnable, Object, boolean)
*/
public InvocationEvent(Object source, Runnable runnable) {
this(source, runnable, null, false);
}
/**
* Constructs an InvocationEvent
with the specified
* source which will execute the runnable's run
* method when dispatched. If notifier is non-null
,
* notifyAll()
will be called on it
* immediately after run
has returned or thrown an exception.
*
An invocation of the form InvocationEvent(source, * runnable, notifier, catchThrowables) * behaves in exactly the same way as the invocation of * {@link #InvocationEvent(Object, int, Runnable, Object, boolean) InvocationEvent}(source, InvocationEvent.INVOCATION_DEFAULT, runnable, notifier, catchThrowables). *
This method throws an IllegalArgumentException
* if source
is null
.
*
* @param source The Object
that originated
* the event
* @param runnable The Runnable
whose
* run
method will be
* executed
* @param notifier The {@code Object} whose notifyAll
* method will be called after
* Runnable.run
has returned or
* thrown an exception
* @param catchThrowables Specifies whether dispatch
* should catch Throwable when executing
* the Runnable
's run
* method, or should instead propagate those
* Throwables to the EventDispatchThread's
* dispatch loop
* @throws IllegalArgumentException if source
is null
*
* @see #getSource()
* @see #InvocationEvent(Object, int, Runnable, Object, boolean)
*/
public InvocationEvent(Object source, Runnable runnable, Object notifier,
boolean catchThrowables) {
this(source, INVOCATION_DEFAULT, runnable, notifier, catchThrowables);
}
/**
* Constructs an InvocationEvent
with the specified
* source and ID which will execute the runnable's run
* method when dispatched. If notifier is non-null
,
* notifyAll
will be called on it immediately after
* run
has returned or thrown an exception.
*
This method throws an
* IllegalArgumentException
if source
* is null
.
*
* @param source The Object
that originated
* the event
* @param id An integer indicating the type of event.
* For information on allowable values, see
* the class description for {@link InvocationEvent}
* @param runnable The Runnable
whose
* run
method will be executed
* @param notifier The Object
whose notifyAll
* method will be called after
* Runnable.run
has returned or
* thrown an exception
* @param catchThrowables Specifies whether dispatch
* should catch Throwable when executing the
* Runnable
's run
* method, or should instead propagate those
* Throwables to the EventDispatchThread's
* dispatch loop
* @throws IllegalArgumentException if source
is null
* @see #getSource()
* @see #getID()
*/
protected InvocationEvent(Object source, int id, Runnable runnable,
Object notifier, boolean catchThrowables) {
super(source, id);
this.runnable = runnable;
this.notifier = notifier;
this.catchExceptions = catchThrowables;
this.when = System.currentTimeMillis();
}
/**
* Executes the Runnable's run()
method and notifies the
* notifier (if any) when run()
has returned or thrown an exception.
*
* @see #isDispatched
*/
public void dispatch() {
try {
if (catchExceptions) {
try {
runnable.run();
}
catch (Throwable t) {
if (t instanceof Exception) {
exception = (Exception) t;
}
throwable = t;
}
}
else {
runnable.run();
}
} finally {
dispatched = true;
if (notifier != null) {
synchronized (notifier) {
notifier.notifyAll();
}
}
}
}
/**
* Returns any Exception caught while executing the Runnable's run()
*
method.
*
* @return A reference to the Exception if one was thrown; null if no
* Exception was thrown or if this InvocationEvent does not
* catch exceptions
*/
public Exception getException() {
return (catchExceptions) ? exception : null;
}
/**
* Returns any Throwable caught while executing the Runnable's run()
*
method.
*
* @return A reference to the Throwable if one was thrown; null if no
* Throwable was thrown or if this InvocationEvent does not
* catch Throwables
* @since 1.5
*/
public Throwable getThrowable() {
return (catchExceptions) ? throwable : null;
}
/**
* Returns the timestamp of when this event occurred.
*
* @return this event's timestamp
* @since 1.4
*/
public long getWhen() {
return when;
}
/**
* Returns {@code true} if the event is dispatched or any exception is
* thrown while dispatching, {@code false} otherwise. The method should
* be called by a waiting thread that calls the {@code notifier.wait()} method.
* Since spurious wakeups are possible (as explained in {@link Object#wait()}),
* this method should be used in a waiting loop to ensure that the event
* got dispatched:
*
* while (!event.isDispatched()) { * notifier.wait(); * } ** If the waiting thread wakes up without dispatching the event, * the {@code isDispatched()} method returns {@code false}, and * the {@code while} loop executes once more, thus, causing * the awakened thread to revert to the waiting mode. *
* If the {@code notifier.notifyAll()} happens before the waiting thread * enters the {@code notifier.wait()} method, the {@code while} loop ensures * that the waiting thread will not enter the {@code notifier.wait()} method. * Otherwise, there is no guarantee that the waiting thread will ever be woken * from the wait. * * @return {@code true} if the event has been dispatched, or any exception * has been thrown while dispatching, {@code false} otherwise * @see #dispatch * @see #notifier * @see #catchExceptions * @since 1.7 */ public boolean isDispatched() { return dispatched; } /** * Returns a parameter string identifying this event. * This method is useful for event-logging and for debugging. * * @return A string identifying the event and its attributes */ public String paramString() { String typeStr; switch(id) { case INVOCATION_DEFAULT: typeStr = "INVOCATION_DEFAULT"; break; default: typeStr = "unknown type"; } return typeStr + ",runnable=" + runnable + ",notifier=" + notifier + ",catchExceptions=" + catchExceptions + ",when=" + when; } }