我正在尝试组织filter chain的EventQueue.dispatchEvent。 java.io.FilterInputStream或javax.servlet.Filter之类的东西。
发现EventQueueDelegate.Delegate是否打算用于此操作?
自Java SE 1.1以来,这种“临时破解”是否尚未解决?
我也期待java.awt.EventDispatchThread进行链式调用。但由于此方法受到保护,因此似乎不适合此方法,并且需要与铃鼓进行额外的跳舞才能使事情正常进行,并且代码变得不太可爱。
有更好的解决方案吗?
最佳答案
接下来是围绕EventQueueDelegate的铃鼓跳舞.Delegate ...
AwtExceptionHandler.java
package example;
/**
* @see java.awt.EventDispatchThread#handleException(Throwable thrown)
*/
public interface AwtExceptionHandler {
void handle(Throwable t) throws Throwable;
}
FilterEventQueueDelegate.java
package example;
import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.lang.reflect.Method;
import java.util.ConcurrentModificationException;
import sun.awt.EventQueueDelegate;
/**
* Aims to organise filter chain of {@link EventQueueDelegate.Delegate}.
*
* <pre>
* private static final AwtResponsivenessMonitor instance = FilterEventQueueDelegate.chain(new AwtResponsivenessMonitor());
* </pre>
*
* @author Mykhaylo Adamovych
*/
public abstract class FilterEventQueueDelegate implements EventQueueDelegate.Delegate, AwtExceptionHandler {
public static final class ExceptionHandler {
private static AwtExceptionHandler currentExceptionHandler;
public void handle(Throwable t) throws Throwable {
currentExceptionHandler.handle(t);
}
}
private static final class SimpleFilterEventQueueDelegate extends FilterEventQueueDelegate {
private EventQueueDelegate.Delegate thirdPartyDelegate;
private Object thirdPartyExceptionHandler;
@Override
public void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
if (thirdPartyDelegate != null)
thirdPartyDelegate.afterDispatch(arg0, arg1);
}
@Override
public Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
if (thirdPartyDelegate != null)
return thirdPartyDelegate.beforeDispatch(arg0);
return arg0;
}
@Override
public AWTEvent getNextEvent(EventQueue arg0) throws InterruptedException {
if (thirdPartyDelegate != null)
return thirdPartyDelegate.getNextEvent(arg0);
return arg0.getNextEvent();
}
@Override
public void handle(Throwable t) throws Throwable {
if (thirdPartyExceptionHandler != null)
try {
Class<? extends Object> c = thirdPartyExceptionHandler.getClass();
Method m = c.getMethod("handle", new Class[] { Throwable.class });
m.invoke(thirdPartyExceptionHandler, new Object[] { t });
} catch (Throwable x) {
thirdPartyExceptionHandler = null; /* Do not try this again */
throw t;
}
else
throw t;
}
public void setEventQueueDelegate(EventQueueDelegate.Delegate delegate) {
thirdPartyDelegate = delegate;
}
public void setExceptionHandler(Object exceptionHandler) {
thirdPartyExceptionHandler = exceptionHandler;
}
}
public static <T extends FilterEventQueueDelegate> T chain(T delegate) {
synchronized (EventQueueDelegate.class) {
EventQueueDelegate.Delegate currentDelegate = EventQueueDelegate.getDelegate();
FilterEventQueueDelegate currentFilterDelegate = null;
if (currentDelegate instanceof FilterEventQueueDelegate)
currentFilterDelegate = (FilterEventQueueDelegate) currentDelegate;
else {
SimpleFilterEventQueueDelegate simpleFilterDelegate = new SimpleFilterEventQueueDelegate();
if (currentDelegate != null)
simpleFilterDelegate.setEventQueueDelegate(currentDelegate);
Object currentExceptionHandler = null;
try {
currentExceptionHandler = Class.forName(System.getProperty("sun.awt.exception.handler")).newInstance();
} catch (Exception e) {
}
if (currentExceptionHandler != null)
simpleFilterDelegate.setExceptionHandler(currentExceptionHandler);
System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());
currentFilterDelegate = simpleFilterDelegate;
}
delegate.setNext(currentFilterDelegate);
EventQueueDelegate.setDelegate(delegate);
if (EventQueueDelegate.getDelegate() != delegate)
throw new ConcurrentModificationException();
ExceptionHandler.currentExceptionHandler = delegate;
return delegate;
}
}
protected FilterEventQueueDelegate next;
@Override
public void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
next.afterDispatch(arg0, arg1);
}
@Override
public Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
return next.beforeDispatch(arg0);
}
@Override
public AWTEvent getNextEvent(EventQueue arg0) throws InterruptedException {
return next.getNextEvent(arg0);
}
@Override
public void handle(Throwable t) throws Throwable {
next.handle(t);
}
private void setNext(FilterEventQueueDelegate eventQueueDelegate) {
next = eventQueueDelegate;
}
}
AwtResponsivenessMonitor.java
package example;
import java.awt.AWTEvent;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* Monitors {@code EventDispatchThread} responsiveness.
* <p>
* Singleton is initialised on first access.
*
* @author Mykhaylo Adamovych
*/
public class AwtResponsivenessMonitor extends FilterEventQueueDelegate {
private static final class DeamonThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread result = new Thread(r);
result.setName(AwtResponsivenessMonitor.class.getSimpleName());
result.setDaemon(true);
return result;
}
}
private static final class NotResponsive extends RuntimeException {
private static final long serialVersionUID = -1445765918431458354L;
}
public static final long DEFAULT_RESPONSIVENESS_TIMEOUT_S = 2;
public static final long RESPONSIVENESS_WATCHDOG_MS = 50;
private static final AwtResponsivenessMonitor instance = FilterEventQueueDelegate.chain(new AwtResponsivenessMonitor());
public static AwtResponsivenessMonitor getInstance() {
return instance;
}
public static long getResponsivenessTimeout() {
return instance.responsivenessTimeoutMs.get();
}
public static void setResponsivenessTimeout(long timeoutMs) {
instance.responsivenessTimeoutMs.set(timeoutMs);
}
private final AtomicLong responsivenessTimeoutMs = new AtomicLong(TimeUnit.SECONDS.toMillis(DEFAULT_RESPONSIVENESS_TIMEOUT_S));
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new DeamonThreadFactory());
private long eventDispatchStartTime;
private Thread currentWorkingThread;
public AwtResponsivenessMonitor() {
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
checkResponsiveness();
}
}, RESPONSIVENESS_WATCHDOG_MS, RESPONSIVENESS_WATCHDOG_MS, TimeUnit.MILLISECONDS);
}
@Override
public synchronized void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
eventDispatchStartTime = 0;
super.afterDispatch(arg0, arg1);
}
@Override
public synchronized Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
eventDispatchStartTime = System.currentTimeMillis();
currentWorkingThread = Thread.currentThread();
return super.beforeDispatch(arg0);
}
private synchronized void checkResponsiveness() {
if (eventDispatchStartTime != 0 && currentWorkingThread != null && System.currentTimeMillis() > eventDispatchStartTime + responsivenessTimeoutMs.get()) {
Exception e = new NotResponsive();
e.setStackTrace(currentWorkingThread.getStackTrace());
e.printStackTrace();
currentWorkingThread = null;
}
}
@Override
public synchronized void handle(Throwable t) throws Throwable {
eventDispatchStartTime = 0;
super.handle(t);
}
}
AwtIdleTracker.java
package example;
import java.awt.AWTEvent;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;
import javax.swing.SwingUtilities;
import sun.awt.SunToolkit;
/**
* Tracks {@code EventDispatchThread} idleness.
* <p>
* Singleton is initialised on first access.
*
* @author Mykhaylo Adamovych
*/
public class AwtIdleTracker extends FilterEventQueueDelegate {
public static final long DEFAULT_IDLE_TIME_TO_TRACK_MS = 1000;
private static final long IDLE_TIME_WATCHDOG_MS = 10;
private static final AwtIdleTracker instance = FilterEventQueueDelegate.chain(new AwtIdleTracker());
public static AwtIdleTracker getInstance() {
return instance;
}
private volatile boolean inProgress;
private final AtomicLong lastDispatchTime = new AtomicLong(0);
@Override
public void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
lastDispatchTime.set(System.currentTimeMillis());
inProgress = false;
super.afterDispatch(arg0, arg1);
}
@Override
public Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
inProgress = true;
return super.beforeDispatch(arg0);
}
@Override
public void handle(Throwable t) throws Throwable {
lastDispatchTime.set(System.currentTimeMillis());
inProgress = false;
super.handle(t);
}
public boolean isIdle() {
return this.isIdle(DEFAULT_IDLE_TIME_TO_TRACK_MS);
}
public boolean isIdle(long idleTimeToTrackMs) {
return !inProgress && SunToolkit.isPostEventQueueEmpty() && System.currentTimeMillis() > lastDispatchTime.get() + idleTimeToTrackMs;
}
public void waitForIdle() {
waitForIdle(DEFAULT_IDLE_TIME_TO_TRACK_MS);
}
public void waitForIdle(long idleTimeToTrackMs) {
waitForIdle(idleTimeToTrackMs, TimeUnit.DAYS.toMillis(365));
}
public void waitForIdle(long idleTimeToTrackMs, long timeoutMs) {
if (SwingUtilities.isEventDispatchThread())
throw new IllegalAccessError();
long staleThreshold = System.currentTimeMillis() + timeoutMs;
while (!isIdle(idleTimeToTrackMs)) {
if (System.currentTimeMillis() > staleThreshold)
throw new RuntimeException("GUI still is not idle.");
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(IDLE_TIME_WATCHDOG_MS));
}
}
}
范例.java
package example;
import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import sun.awt.EventQueueDelegate;
public class Example {
public static class ThirdPartyEventQueueDelegate implements EventQueueDelegate.Delegate {
public static final void registerEventQueueDelegate() {
EventQueueDelegate.setDelegate(new ThirdPartyEventQueueDelegate());
}
@Override
public void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
System.out.println("Third party even queue delegate was not broken.");
}
@Override
public Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
return arg0;
}
@Override
public AWTEvent getNextEvent(EventQueue arg0) throws InterruptedException {
return arg0.getNextEvent();
}
}
public static class ThirdPartyExceptionHandler {
public static void registerExceptionHandler() {
System.setProperty("sun.awt.exception.handler", ThirdPartyExceptionHandler.class.getName());
}
public void handle(Throwable t) {
System.out.println("Third party Exception handler was not broken.");
}
}
private static boolean wasIdle = false;
private static boolean isFistTime = true;
public static synchronized void log(String msg) {
System.out.println(new SimpleDateFormat("mm:ss.SSS").format(new Date()) + "\t" + msg);
}
public static void main(String[] args) {
// let suppose there are some related stuff already
ThirdPartyExceptionHandler.registerExceptionHandler();
ThirdPartyEventQueueDelegate.registerEventQueueDelegate();
// initialise singletons, build filter chain
AwtIdleTracker.getInstance();
AwtResponsivenessMonitor.setResponsivenessTimeout(TimeUnit.SECONDS.toMillis(2));
testWaitForIdle();
// testSomeGui();
}
public static void testSomeGui() {
// some test with visible GUI
JFrame frame = new JFrame();
frame.setSize(300, 300);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
while (true) {
boolean isIdle = AwtIdleTracker.getInstance().isIdle();
if (isFistTime || wasIdle != isIdle) {
isFistTime = false;
wasIdle = isIdle;
String msg = isIdle
? "idle"
: "busy";
log("system becomes " + msg);
}
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1));
}
}
public static void testWaitForIdle() {
// some long operation
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
log("task started");
// throw new RuntimeException();
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
log("task finished");
}
});
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
log("started waiting for idle");
AwtIdleTracker.getInstance().waitForIdle();
log("stopped waiting for idle");
}
}
关于java - Swing中的事件调度筛选器链,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8080018/