2011-11-10 5 views
2

filter chainEventQueue.dispatchEventに整理しようとしています。 java.io.FilterInputStreamまたはjavax.servlet.Filterのようなものです。スウィングのイベントディスパッチフィルターチェーン

は?EventQueueDelegate.Delegateはこのためのものであることが判明..しかしEventQueue.dispatchEventEventQueueDelegate.Delegateでの例外の場合には、この醜いjava.awt.EventDispatchThread.handleExceptionについて何がシーンに表示されません知っています。

  • この「一時的なハック」はまだJava SE 1.1以降で解決されていませんか?

私はまた、EventQueue.dispatchEventを呼び出してチェーンをコールしました。しかし、この方法は保護されているため、これには適していないように見え、タンバリンとの追加ダンスが必要となり、コードが素敵になりません。

  • もっと良い解決策はありますか?
  • 次はEventQueueDelegate.Delegate周りのタンバリンで踊っている
+0

私の質問なぜ、btwメソッド 'push()' – mKorbel

+0

私はEDTの忙しさをテスト目的で追跡したい。しかし、すでにカスタムのEventQueueがシステムに登録されています。だから私は新しいものを追加し、以前のものを壊さないようにする必要があります。 –

+0

push() '既存のEventQueueを置き換えますが、私はフィルタ層が必要です。 –

答えて

1

...

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); 
    } 
} 
0ここでは、テスト中のテストやアプリケーションを同期するに

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

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"); 
    } 
} 
+0

コードの場合は+1、時間が1分の理由はなぜですか?invokeAndWait() – mKorbel

+0

統合テストを実行するときEDTがGUIの再構築を待つ必要があり、ボタンのラベルテキストをアサートする必要があります。また、私はバックグラウンドタスクが完了するのを待っていますが、これは別の話です。 invokeAndWait()は、現在EventQueueに追加されているイベントのディスパッチを待機します。しかし、いくつかのイベントを処理中に新しいものがキューに追加され、この処理がGUIコントロールツリーを完全に再構築するのと同じくらい重要な場合はどうなりますか? –

+0

1)( 'EDTを待つ必要のある統合テストを実行する) 'javax.swing.Action'、2)('バックグラウンドタスクは完了しますが、 ')、javax.swingから' javax.swing.Action'を呼び出すことがあります。Timer' – mKorbel

関連する問題