事件分派在Swing过滤器链 [英] Event dispatching filter chain in Swing

查看:118
本文介绍了事件分派在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 =htt​​p://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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆