事件分派在Swing过滤器链 [英] Event dispatching filter chain in Swing
问题描述
我想举办的<一个过滤器链 href=\"http://download.oracle.com/javase/6/docs/api/java/awt/EventQueue.html#dispatchEvent%28java.awt.AWTEvent%29\"相对=nofollow> EventQueue.dispatchEvent 。像 java.io.FilterInputStream中或< A HREF =http://download.oracle.com/javaee/6/api/javax/servlet/Filter.html相对=nofollow> javax.servlet.Filter的。
I'm trying to organize filter chain of EventQueue.dispatchEvent. Something like java.io.FilterInputStream or javax.servlet.Filter.
EventQueueDelegate被用于这一.Delegate ?..但在例外的情况下, EventQueue.dispatchEvent
EventQueueDelegate.Delegate
就知道这又丑没什么<一个href=\"http://javasource$c$c.org/html/open-source/jdk/jdk-6u23/java/awt/EventDispatchThread.java.html\"相对=nofollow> java.awt.EventDispatchThread .handleException
出现在现场。
Found EventQueueDelegate.Delegate to be intended for this?.. But in case of exception in EventQueue.dispatchEvent
EventQueueDelegate.Delegate
it knows nothing about this and ugly java.awt.EventDispatchThread.handleException
appears on the scene.
- 这是暂时的黑客还没有,因为解决的Java SE 1.1 ??? !!!
我也看了朝<一个href=\"http://download.oracle.com/javase/6/docs/api/java/awt/EventQueue.html#dispatchEvent%28java.awt.AWTEvent%29\"相对=nofollow> EventQueue.dispatchEvent 以连锁调用。但它似乎不适合这个由于这种方法是受保护的,它需要额外的舞蹈与手鼓,使事情工作,code变得不那么可爱。
I've also looked toward EventQueue.dispatchEvent to call in chain. But it appeared not suitable for this due to this method is protected and it require additional dancing with tambourines to make things work and code becomes not so lovely.
- 任何更好的解决方案?
推荐答案
接下来与手鼓舞蹈各地EventQueueDelegate.Delegate ...
Next is dancing with tambourines around EventQueueDelegate.Delegate...
AwtExceptionHandler.java
AwtExceptionHandler.java
package example;
/**
* @see java.awt.EventDispatchThread#handleException(Throwable thrown)
*/
public interface AwtExceptionHandler {
void handle(Throwable t) throws Throwable;
}
FilterEventQueueDelegate.java
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
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
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));
}
}
}
Example.java
Example.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");
}
}
这篇关于事件分派在Swing过滤器链的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!