6638195: need API for EventQueueDelegate
authoridk
Fri, 25 Jul 2008 14:13:59 -0400
changeset 1293 ef349b440fc9
parent 1292 e91af84fbe9f
child 1294 16088ec1b9e7
6638195: need API for EventQueueDelegate Reviewed-by: bchristi
jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java
jdk/src/share/classes/java/awt/EventDispatchThread.java
jdk/src/share/classes/sun/awt/EventQueueDelegate.java
jdk/test/java/awt/EventQueue/6638195/bug6638195.java
--- a/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java	Fri Jul 25 21:00:05 2008 +0400
+++ b/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java	Fri Jul 25 14:13:59 2008 -0400
@@ -25,7 +25,12 @@
 
 package com.sun.java.swing;
 
+import sun.awt.EventQueueDelegate;
 import sun.awt.AppContext;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.awt.AWTEvent;
+import java.awt.EventQueue;
 import java.awt.Component;
 import javax.swing.JComponent;
 import javax.swing.RepaintManager;
@@ -88,4 +93,82 @@
         }
         return delegate;
     }
+
+    /*
+     * We use maps to avoid reflection. Hopefully it should perform better
+     * this way.
+     */
+    public static void setEventQueueDelegate(
+            Map<String, Map<String, Object>> map) {
+        EventQueueDelegate.setDelegate(new EventQueueDelegateFromMap(map));
+    }
+
+    private static class EventQueueDelegateFromMap
+    implements EventQueueDelegate.Delegate {
+        private final AWTEvent[] afterDispatchEventArgument;
+        private final Object[] afterDispatchHandleArgument;
+        private final Callable<Void> afterDispatchCallable;
+
+        private final AWTEvent[] beforeDispatchEventArgument;
+        private final Callable<Object> beforeDispatchCallable;
+
+        private final EventQueue[] getNextEventEventQueueArgument;
+        private final Callable<AWTEvent> getNextEventCallable;
+
+        @SuppressWarnings("unchecked")
+        public EventQueueDelegateFromMap(Map<String, Map<String, Object>> objectMap) {
+            Map<String, Object> methodMap = objectMap.get("afterDispatch");
+            afterDispatchEventArgument = (AWTEvent[]) methodMap.get("event");
+            afterDispatchHandleArgument = (Object[]) methodMap.get("handle");
+            afterDispatchCallable = (Callable<Void>) methodMap.get("method");
+
+            methodMap = objectMap.get("beforeDispatch");
+            beforeDispatchEventArgument = (AWTEvent[]) methodMap.get("event");
+            beforeDispatchCallable = (Callable<Object>) methodMap.get("method");
+
+            methodMap = objectMap.get("getNextEvent");
+            getNextEventEventQueueArgument =
+                (EventQueue[]) methodMap.get("eventQueue");
+            getNextEventCallable = (Callable<AWTEvent>) methodMap.get("method");
+        }
+
+        @Override
+        public void afterDispatch(AWTEvent event, Object handle) {
+            afterDispatchEventArgument[0] = event;
+            afterDispatchHandleArgument[0] = handle;
+            try {
+                afterDispatchCallable.call();
+            } catch (Exception e) {
+                if (e instanceof RuntimeException) {
+                    throw (RuntimeException) e;
+                }
+            }
+        }
+
+        @Override
+        public Object beforeDispatch(AWTEvent event) {
+            beforeDispatchEventArgument[0] = event;
+            try {
+                return beforeDispatchCallable.call();
+            } catch (Exception e) {
+                if (e instanceof RuntimeException) {
+                    throw (RuntimeException) e;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public AWTEvent getNextEvent(EventQueue eventQueue) {
+            getNextEventEventQueueArgument[0] = eventQueue;
+            try {
+                return getNextEventCallable.call();
+            } catch (Exception e) {
+                if (e instanceof RuntimeException) {
+                    throw (RuntimeException) e;
+                }
+            }
+            return null;
+        }
+    }
 }
--- a/jdk/src/share/classes/java/awt/EventDispatchThread.java	Fri Jul 25 21:00:05 2008 +0400
+++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java	Fri Jul 25 14:13:59 2008 -0400
@@ -39,6 +39,7 @@
 import java.util.logging.*;
 
 import sun.awt.dnd.SunDragSourceContextPeer;
+import sun.awt.EventQueueDelegate;
 
 /**
  * EventDispatchThread is a package-private AWT class which takes
@@ -243,10 +244,16 @@
         try {
             AWTEvent event;
             boolean eventOK;
+            EventQueueDelegate.Delegate delegate =
+                EventQueueDelegate.getDelegate();
             do {
-                event = (id == ANY_EVENT)
-                    ? theQueue.getNextEvent()
-                    : theQueue.getNextEvent(id);
+                if (delegate != null && id == ANY_EVENT) {
+                    event = delegate.getNextEvent(theQueue);
+                } else {
+                    event = (id == ANY_EVENT)
+                        ? theQueue.getNextEvent()
+                        : theQueue.getNextEvent(id);
+                }
 
                 eventOK = true;
                 synchronized (eventFilters) {
@@ -272,7 +279,14 @@
                 eventLog.log(Level.FINEST, "Dispatching: " + event);
             }
 
+            Object handle = null;
+            if (delegate != null) {
+                handle = delegate.beforeDispatch(event);
+            }
             theQueue.dispatchEvent(event);
+            if (delegate != null) {
+                delegate.afterDispatch(event, handle);
+            }
             return true;
         }
         catch (ThreadDeath death) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/awt/EventQueueDelegate.java	Fri Jul 25 14:13:59 2008 -0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.awt;
+
+import java.awt.AWTEvent;
+import java.awt.EventQueue;
+
+
+public class EventQueueDelegate {
+    private static final Object EVENT_QUEUE_DELEGATE_KEY =
+        new StringBuilder("EventQueueDelegate.Delegate");
+
+    public static void setDelegate(Delegate delegate) {
+        AppContext.getAppContext().put(EVENT_QUEUE_DELEGATE_KEY, delegate);
+    }
+    public static Delegate getDelegate() {
+        return
+          (Delegate) AppContext.getAppContext().get(EVENT_QUEUE_DELEGATE_KEY);
+    }
+    public interface Delegate {
+        /**
+         * This method allows for changing {@code EventQueue} events order.
+         *
+         * @param eventQueue current {@code EventQueue}
+         * @return next {@code event} for the {@code EventDispatchThread}
+         */
+
+        public AWTEvent getNextEvent(EventQueue eventQueue) throws InterruptedException;
+
+        /**
+         * Notifies delegate before EventQueue.dispatch method.
+         *
+         * Note: this method may mutate the event
+         *
+         * @param event  to be dispatched by {@code dispatch} method
+         * @return handle to be passed to {@code afterDispatch} method
+         */
+        public Object beforeDispatch(AWTEvent event);
+
+        /**
+         * Notifies delegate after EventQueue.dispatch method.
+         *
+         * @param event {@code event} dispatched by the {@code dispatch} method
+         * @param handle object which came from {@code beforeDispatch} method
+         */
+        public void afterDispatch(AWTEvent event, Object handle);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/EventQueue/6638195/bug6638195.java	Fri Jul 25 14:13:59 2008 -0400
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ *
+ * @bug 6638195
+ * @author Igor Kushnirskiy
+ * @summary tests if EventQueueDelegate.Delegate is invoked.
+ */
+
+import sun.awt.EventQueueDelegate;
+import com.sun.java.swing.SwingUtilities3;
+
+import java.util.*;
+import java.util.concurrent.*;
+import java.awt.*;
+
+public class bug6638195 {
+    public static void main(String[] args) throws Exception {
+        MyEventQueueDelegate delegate = new MyEventQueueDelegate();
+        EventQueueDelegate.setDelegate(delegate);
+        runTest(delegate);
+
+        delegate = new MyEventQueueDelegate();
+        SwingUtilities3.setEventQueueDelegate(getObjectMap(delegate));
+        runTest(delegate);
+    }
+
+    private static void runTest(MyEventQueueDelegate delegate) throws Exception {
+        EventQueue.invokeLater(
+            new Runnable() {
+                public void run() {
+                }
+            });
+        final CountDownLatch latch = new CountDownLatch(1);
+        EventQueue.invokeLater(
+            new Runnable() {
+                public void run() {
+                    latch.countDown();
+                }
+            });
+        latch.await();
+        if (! delegate.allInvoked()) {
+            throw new RuntimeException("failed");
+        }
+    }
+
+    static Map<String, Map<String, Object>> getObjectMap(
+          final EventQueueDelegate.Delegate delegate) {
+        Map<String, Map<String, Object>> objectMap =
+            new HashMap<String, Map<String, Object>>();
+        Map<String, Object> methodMap;
+
+        final AWTEvent[] afterDispatchEventArgument = new AWTEvent[1];
+        final Object[] afterDispatchHandleArgument = new Object[1];
+        Callable<Void> afterDispatchCallable =
+            new Callable<Void>() {
+                public Void call() {
+                    delegate.afterDispatch(afterDispatchEventArgument[0],
+                                           afterDispatchHandleArgument[0]);
+                    return null;
+                }
+            };
+        methodMap = new HashMap<String, Object>();
+        methodMap.put("event", afterDispatchEventArgument);
+        methodMap.put("handle", afterDispatchHandleArgument);
+        methodMap.put("method", afterDispatchCallable);
+        objectMap.put("afterDispatch", methodMap);
+
+        final AWTEvent[] beforeDispatchEventArgument = new AWTEvent[1];
+        Callable<Object> beforeDispatchCallable =
+            new Callable<Object>() {
+                public Object call() {
+                    return delegate.beforeDispatch(
+                        beforeDispatchEventArgument[0]);
+                }
+            };
+        methodMap = new HashMap<String, Object>();
+        methodMap.put("event", beforeDispatchEventArgument);
+        methodMap.put("method", beforeDispatchCallable);
+        objectMap.put("beforeDispatch", methodMap);
+
+        final EventQueue[] getNextEventEventQueueArgument = new EventQueue[1];
+        Callable<AWTEvent> getNextEventCallable =
+            new Callable<AWTEvent>() {
+                public AWTEvent call() throws Exception {
+                    return delegate.getNextEvent(
+                        getNextEventEventQueueArgument[0]);
+                }
+            };
+        methodMap = new HashMap<String, Object>();
+        methodMap.put("eventQueue", getNextEventEventQueueArgument);
+        methodMap.put("method", getNextEventCallable);
+        objectMap.put("getNextEvent", methodMap);
+
+        return objectMap;
+    }
+    static class MyEventQueueDelegate implements EventQueueDelegate.Delegate {
+        private volatile boolean getNextEventInvoked = false;
+        private volatile boolean beforeDispatchInvoked = false;
+        private volatile boolean afterDispatchInvoked = false;
+        public AWTEvent getNextEvent(EventQueue eventQueue)
+              throws InterruptedException {
+            getNextEventInvoked = true;
+            return eventQueue.getNextEvent();
+        }
+        public Object beforeDispatch(AWTEvent event) {
+            beforeDispatchInvoked = true;
+            return null;
+        }
+        public void afterDispatch(AWTEvent event, Object handle) {
+            afterDispatchInvoked = true;
+        }
+        private boolean allInvoked() {
+            return getNextEventInvoked && beforeDispatchInvoked && afterDispatchInvoked;
+        }
+    }
+}