jdk/test/sanity/client/lib/jemmy/src/org/netbeans/jemmy/QueueTool.java
changeset 36744 a00905527ec2
equal deleted inserted replaced
36743:bdc3f1b79fb7 36744:a00905527ec2
       
     1 /*
       
     2  * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 package org.netbeans.jemmy;
       
    24 
       
    25 import java.awt.AWTEvent;
       
    26 import java.awt.EventQueue;
       
    27 import java.awt.Toolkit;
       
    28 import java.awt.event.InvocationEvent;
       
    29 import java.lang.reflect.InvocationTargetException;
       
    30 
       
    31 /**
       
    32  *
       
    33  * Provides functionality to work with java.awt.EventQueue empty.
       
    34  *
       
    35  * <BR><BR>Timeouts used: <BR>
       
    36  * QueueTool.WaitQueueEmptyTimeout - timeout to wait queue emptied<BR>
       
    37  * QueueTool.QueueCheckingDelta - time delta to check result<BR>
       
    38  * QueueTool.LockTimeout - time to wait queue locked after lock action has been
       
    39  * put there<BR>
       
    40  * QueueTool.InvocationTimeout - time for action was put into queue to be
       
    41  * started<BR>
       
    42  * QueueTool.MaximumLockingTime - maximum time to lock queue.<br>
       
    43  *
       
    44  * @see Timeouts
       
    45  *
       
    46  * @author Alexandre Iline (alexandre.iline@oracle.com)
       
    47  *
       
    48  */
       
    49 public class QueueTool implements Outputable, Timeoutable {
       
    50 
       
    51     private final static long WAIT_QUEUE_EMPTY_TIMEOUT = 180000;
       
    52     private final static long QUEUE_CHECKING_DELTA = 10;
       
    53     private final static long LOCK_TIMEOUT = 180000;
       
    54     private final static long MAXIMUM_LOCKING_TIME = 180000;
       
    55     private final static long INVOCATION_TIMEOUT = 180000;
       
    56 
       
    57     private static JemmyQueue jemmyQueue = null;
       
    58 
       
    59     private TestOut output;
       
    60     private Timeouts timeouts;
       
    61     private Locker locker;
       
    62     private Waiter<String, Void> lockWaiter;
       
    63 
       
    64     /**
       
    65      * Constructor.
       
    66      */
       
    67     public QueueTool() {
       
    68         locker = new Locker();
       
    69         lockWaiter = new Waiter<String, Void>(new Waitable<String, Void>() {
       
    70             @Override
       
    71             public String actionProduced(Void obj) {
       
    72                 return locker.isLocked() ? "" : null;
       
    73             }
       
    74 
       
    75             @Override
       
    76             public String getDescription() {
       
    77                 return "Event queue to be locked";
       
    78             }
       
    79 
       
    80             @Override
       
    81             public String toString() {
       
    82                 return "QueueTool.Waiter{" + getDescription() + '}';
       
    83             }
       
    84         });
       
    85         setOutput(JemmyProperties.getProperties().getOutput());
       
    86         setTimeouts(JemmyProperties.getProperties().getTimeouts());
       
    87     }
       
    88 
       
    89     /**
       
    90      * Returns system EventQueue.
       
    91      *
       
    92      * @return system EventQueue.
       
    93      */
       
    94     public static EventQueue getQueue() {
       
    95         return Toolkit.getDefaultToolkit().getSystemEventQueue();
       
    96     }
       
    97 
       
    98     /**
       
    99      * Map to {@code EventQueue.isDispatchThread()}.
       
   100      *
       
   101      * @return true if this thread is the AWT dispatching thread.
       
   102      */
       
   103     public static boolean isDispatchThread() {
       
   104         return EventQueue.isDispatchThread();
       
   105     }
       
   106 
       
   107     /**
       
   108      * Checks if system event queue is empty.
       
   109      *
       
   110      * @return true if EventQueue is empty.
       
   111      */
       
   112     public static boolean checkEmpty() {
       
   113         return getQueue().peekEvent() == null;
       
   114     }
       
   115 
       
   116     /**
       
   117      * Shortcuts event if
       
   118      * {@code ((JemmyProperties.getCurrentDispatchingModel() & JemmyProperties.SHORTCUT_MODEL_MASK) != 0)}
       
   119      * and if executed in the dispatch thread. Otherwise posts event.
       
   120      *
       
   121      * @param event Event to dispatch.
       
   122      */
       
   123     public static void processEvent(AWTEvent event) {
       
   124         if ((JemmyProperties.getCurrentDispatchingModel()
       
   125                 & JemmyProperties.SHORTCUT_MODEL_MASK) != 0) {
       
   126             installQueue();
       
   127         }
       
   128         if ((JemmyProperties.getCurrentDispatchingModel()
       
   129                 & JemmyProperties.SHORTCUT_MODEL_MASK) != 0
       
   130                 && isDispatchThread()) {
       
   131             shortcutEvent(event);
       
   132         } else {
       
   133             postEvent(event);
       
   134         }
       
   135     }
       
   136 
       
   137     /**
       
   138      * Simply posts events into the system event queue.
       
   139      *
       
   140      * @param event Event to dispatch.
       
   141      */
       
   142     public static void postEvent(AWTEvent event) {
       
   143         getQueue().postEvent(event);
       
   144     }
       
   145 
       
   146     /**
       
   147      * Dispatches event ahead of all events staying in the event queue.
       
   148      *
       
   149      * @param event an event to be shortcut.
       
   150      */
       
   151     public static void shortcutEvent(AWTEvent event) {
       
   152         installQueue();
       
   153         jemmyQueue.shortcutEvent(event);
       
   154     }
       
   155 
       
   156     /**
       
   157      * Installs own Jemmy EventQueue implementation. The method is executed in
       
   158      * dispatchmode only.
       
   159      *
       
   160      * @see #uninstallQueue
       
   161      */
       
   162     public static void installQueue() {
       
   163         if (jemmyQueue == null) {
       
   164             jemmyQueue = new JemmyQueue();
       
   165         }
       
   166         jemmyQueue.install();
       
   167     }
       
   168 
       
   169     /**
       
   170      * Uninstalls own Jemmy EventQueue implementation.
       
   171      *
       
   172      * @see #installQueue
       
   173      */
       
   174     public static void uninstallQueue() {
       
   175         if (jemmyQueue != null) {
       
   176             jemmyQueue.uninstall();
       
   177         }
       
   178     }
       
   179 
       
   180     static {
       
   181         Timeouts.initDefault("QueueTool.WaitQueueEmptyTimeout", WAIT_QUEUE_EMPTY_TIMEOUT);
       
   182         Timeouts.initDefault("QueueTool.QueueCheckingDelta", QUEUE_CHECKING_DELTA);
       
   183         Timeouts.initDefault("QueueTool.LockTimeout", LOCK_TIMEOUT);
       
   184         Timeouts.initDefault("QueueTool.InvocationTimeout", INVOCATION_TIMEOUT);
       
   185         Timeouts.initDefault("QueueTool.MaximumLockingTime", MAXIMUM_LOCKING_TIME);
       
   186     }
       
   187 
       
   188     /**
       
   189      * Defines current timeouts.
       
   190      *
       
   191      * @param ts ?t? A collection of timeout assignments.
       
   192      * @see org.netbeans.jemmy.Timeouts
       
   193      * @see org.netbeans.jemmy.Timeoutable
       
   194      * @see #getTimeouts
       
   195      */
       
   196     @Override
       
   197     public void setTimeouts(Timeouts ts) {
       
   198         timeouts = ts;
       
   199         lockWaiter.setTimeouts(getTimeouts().cloneThis());
       
   200     }
       
   201 
       
   202     /**
       
   203      * Return current timeouts.
       
   204      *
       
   205      * @return the collection of current timeout assignments.
       
   206      * @see org.netbeans.jemmy.Timeouts
       
   207      * @see org.netbeans.jemmy.Timeoutable
       
   208      * @see #setTimeouts
       
   209      */
       
   210     @Override
       
   211     public Timeouts getTimeouts() {
       
   212         return timeouts;
       
   213     }
       
   214 
       
   215     /**
       
   216      * Defines print output streams or writers.
       
   217      *
       
   218      * @param out Identify the streams or writers used for print output.
       
   219      * @see org.netbeans.jemmy.Outputable
       
   220      * @see org.netbeans.jemmy.TestOut
       
   221      * @see #getOutput
       
   222      */
       
   223     @Override
       
   224     public void setOutput(TestOut out) {
       
   225         output = out;
       
   226         lockWaiter.setOutput(output.createErrorOutput());
       
   227     }
       
   228 
       
   229     /**
       
   230      * Returns print output streams or writers.
       
   231      *
       
   232      * @return an object that contains references to objects for printing to
       
   233      * output and err streams.
       
   234      * @see org.netbeans.jemmy.Outputable
       
   235      * @see org.netbeans.jemmy.TestOut
       
   236      * @see #setOutput
       
   237      */
       
   238     @Override
       
   239     public TestOut getOutput() {
       
   240         return output;
       
   241     }
       
   242 
       
   243     /**
       
   244      * Waits for system event queue empty. Uses
       
   245      * "QueueTool.WaitQueueEmptyTimeout" milliseconds to wait.
       
   246      *
       
   247      * @throws TimeoutExpiredException
       
   248      */
       
   249     public void waitEmpty() {
       
   250         Waiter<String, Void> waiter = new Waiter<>(new Waitable<String, Void>() {
       
   251             @Override
       
   252             public String actionProduced(Void obj) {
       
   253                 if (checkEmpty()) {
       
   254                     return "Empty";
       
   255                 }
       
   256                 return null;
       
   257             }
       
   258 
       
   259             @Override
       
   260             public String getDescription() {
       
   261                 return "Wait event queue empty";
       
   262             }
       
   263 
       
   264             @Override
       
   265             public String toString() {
       
   266                 return "waitEmpty.Waiter{" + getDescription() + '}';
       
   267             }
       
   268         });
       
   269         waiter.setTimeoutsToCloneOf(timeouts, "QueueTool.WaitQueueEmptyTimeout");
       
   270         waiter.setOutput(output);
       
   271         try {
       
   272             waiter.waitAction(null);
       
   273         } catch (TimeoutExpiredException e) {
       
   274             final AWTEvent event = getQueue().peekEvent();
       
   275             // if event != null run toString in dispatch thread
       
   276             String eventToString = (event == null) ? "null" : invokeSmoothly(
       
   277                     new QueueTool.QueueAction<String>("event.toString()") {
       
   278                 @Override
       
   279                 public String launch() {
       
   280                     return event.toString();
       
   281                 }
       
   282             }
       
   283             );
       
   284             getOutput().printErrLine("Event at the top of stack: " + eventToString);
       
   285             throw (e);
       
   286         } catch (InterruptedException e) {
       
   287             output.printStackTrace(e);
       
   288         }
       
   289     }
       
   290 
       
   291     /**
       
   292      * Waits for system event queue be empty for {@code emptyTime}
       
   293      * milliseconds. Uses "QueueTool.WaitQueueEmptyTimeout" milliseconds to
       
   294      * wait.
       
   295      *
       
   296      * @param emptyTime time for the queue to stay empty.
       
   297      * @throws TimeoutExpiredException
       
   298      */
       
   299     public void waitEmpty(long emptyTime) {
       
   300 
       
   301         StayingEmptyWaiter waiter = new StayingEmptyWaiter(emptyTime);
       
   302         waiter.setTimeoutsToCloneOf(timeouts, "QueueTool.WaitQueueEmptyTimeout");
       
   303         waiter.setOutput(output);
       
   304         try {
       
   305             waiter.waitAction(null);
       
   306         } catch (TimeoutExpiredException e) {
       
   307             final AWTEvent event = getQueue().peekEvent();
       
   308             String eventToString = (event == null) ? "null" : invokeSmoothly(
       
   309                     new QueueTool.QueueAction<String>("event.toString()") {
       
   310                 @Override
       
   311                 public String launch() {
       
   312                     return event.toString();
       
   313                 }
       
   314             }
       
   315             );
       
   316             getOutput().printErrLine("Event at the top of stack: " + eventToString);
       
   317             throw (e);
       
   318         } catch (InterruptedException e) {
       
   319             output.printStackTrace(e);
       
   320         }
       
   321     }
       
   322 
       
   323     /**
       
   324      * Invokes action through EventQueue. Does not wait for it execution.
       
   325      *
       
   326      * @param action an action to be invoked.
       
   327      */
       
   328     public void invoke(QueueAction<?> action) {
       
   329         output.printTrace("Invoking \"" + action.getDescription() + "\" action through event queue");
       
   330         EventQueue.invokeLater(action);
       
   331     }
       
   332 
       
   333     /**
       
   334      * Invokes runnable through EventQueue. Does not wait for it execution.
       
   335      *
       
   336      * @param runnable a runnable to be invoked.
       
   337      * @return QueueAction instance which can be use for execution monitoring.
       
   338      * @see QueueTool.QueueAction
       
   339      */
       
   340     public QueueAction<Void> invoke(Runnable runnable) {
       
   341         QueueAction<Void> result = new RunnableRunnable(runnable);
       
   342         invoke(result);
       
   343         return result;
       
   344     }
       
   345 
       
   346     /**
       
   347      * Invokes action through EventQueue. Does not wait for it execution.
       
   348      *
       
   349      * @param action an action to be invoked.
       
   350      * @param param {@code action.launch(Object)} method parameter.
       
   351      * @return QueueAction instance which can be use for execution monitoring.
       
   352      * @see QueueTool.QueueAction
       
   353      */
       
   354     public <R, P> QueueAction<R> invoke(Action<R, P> action, P param) {
       
   355         QueueAction<R> result = new ActionRunnable<>(action, param);
       
   356         invoke(result);
       
   357         return result;
       
   358     }
       
   359 
       
   360     /**
       
   361      * Being executed outside of AWT dispatching thread, invokes an action
       
   362      * through the event queue. Otherwise executes {@code action.launch()}
       
   363      * method directly.
       
   364      *
       
   365      * @param action anaction to be executed.
       
   366      * @return Action result.
       
   367      */
       
   368     public <R> R invokeSmoothly(QueueAction<R> action) {
       
   369         if (!EventQueue.isDispatchThread()) {
       
   370             return invokeAndWait(action);
       
   371         } else {
       
   372             try {
       
   373                 return action.launch();
       
   374             } catch (Exception e) {
       
   375                 throw (new JemmyException("Exception in " + action.getDescription(), e));
       
   376             }
       
   377         }
       
   378     }
       
   379 
       
   380     /**
       
   381      * Being executed outside of AWT dispatching thread, invokes a runnable
       
   382      * through the event queue. Otherwise executes {@code runnable.run()}
       
   383      * method directly.
       
   384      *
       
   385      * @param runnable a runnable to be executed.
       
   386      */
       
   387     public void invokeSmoothly(Runnable runnable) {
       
   388         if (!EventQueue.isDispatchThread()) {
       
   389             invokeAndWait(runnable);
       
   390         } else {
       
   391             runnable.run();
       
   392         }
       
   393     }
       
   394 
       
   395     /**
       
   396      * Being executed outside of AWT dispatching thread, invokes an action
       
   397      * through the event queue. Otherwise executes
       
   398      * {@code action.launch(Object)} method directly.
       
   399      *
       
   400      * @param action anaction to be executed.
       
   401      * @param param an action parameter
       
   402      * @return Action result.
       
   403      */
       
   404     public <R, P> R invokeSmoothly(Action<R, P> action, P param) {
       
   405         if (!EventQueue.isDispatchThread()) {
       
   406             return invokeAndWait(action, param);
       
   407         } else {
       
   408             return action.launch(param);
       
   409         }
       
   410     }
       
   411 
       
   412     /**
       
   413      * Invokes action through EventQueue. Waits for it execution.
       
   414      *
       
   415      * @param action an action to be invoked.
       
   416      * @return a result of action
       
   417      * @throws TimeoutExpiredException if action was not executed in
       
   418      * "QueueTool.InvocationTimeout" milliseconds.
       
   419      */
       
   420     public <R> R invokeAndWait(QueueAction<R> action) {
       
   421 
       
   422         class JemmyInvocationLock {
       
   423         }
       
   424         Object lock = new JemmyInvocationLock();
       
   425         InvocationEvent event
       
   426                 = new JemmyInvocationEvent(Toolkit.getDefaultToolkit(),
       
   427                         action,
       
   428                         lock,
       
   429                         true);
       
   430         try {
       
   431             synchronized (lock) {
       
   432                 getQueue().postEvent(event);
       
   433                 while (!action.getFinished()) {
       
   434                     lock.wait();
       
   435                 }
       
   436             }
       
   437         } catch (InterruptedException e) {
       
   438             throw (new JemmyException("InterruptedException during "
       
   439                     + action.getDescription()
       
   440                     + " execution", e));
       
   441         }
       
   442         if (action.getException() != null) {
       
   443             throw (new JemmyException("Exception in " + action.getDescription(),
       
   444                     action.getException()));
       
   445         }
       
   446         if (event.getException() != null) {
       
   447             throw (new JemmyException("Exception in " + action.getDescription(),
       
   448                     event.getException()));
       
   449         }
       
   450         return action.getResult();
       
   451     }
       
   452 
       
   453     public static final class JemmyInvocationEvent extends InvocationEvent {
       
   454 
       
   455         private static final long serialVersionUID = 42L;
       
   456 
       
   457         public JemmyInvocationEvent(Object source, Runnable runnable,
       
   458                 Object notifier, boolean catchThrowables) {
       
   459             super(source, runnable, notifier, catchThrowables);
       
   460         }
       
   461     }
       
   462 
       
   463     /**
       
   464      * Invokes runnable through EventQueue. Waits for it execution.
       
   465      *
       
   466      * @param runnable a runnable to be invoked.
       
   467      * @throws TimeoutExpiredException if runnable was not executed in
       
   468      * "QueueTool.InvocationTimeout" milliseconds.
       
   469      */
       
   470     public void invokeAndWait(Runnable runnable) {
       
   471         invokeAndWait(new RunnableRunnable(runnable));
       
   472     }
       
   473 
       
   474     /**
       
   475      * Invokes action through EventQueue. Waits for it execution. May throw
       
   476      * TimeoutExpiredException if action was not executed in
       
   477      * "QueueTool.InvocationTimeout" milliseconds.
       
   478      *
       
   479      * @param action an action to be invoked.
       
   480      * @param param action.launch(Object method parameter.
       
   481      * @return a result of action
       
   482      * @throws TimeoutExpiredException if action was not executed in
       
   483      * "QueueTool.InvocationTimeout" milliseconds.
       
   484      */
       
   485     public <R, P> R invokeAndWait(Action<R, P> action, P param) {
       
   486         return invokeAndWait(new ActionRunnable<>(action, param));
       
   487     }
       
   488 
       
   489     /**
       
   490      * Locks EventQueue. Locking will be automatically aborted after
       
   491      * "QueueTool.MaximumLockingTime" milliseconds.
       
   492      *
       
   493      * @see #unlock()
       
   494      * @throws TimeoutExpiredException
       
   495      */
       
   496     public void lock() {
       
   497         output.printTrace("Locking queue.");
       
   498         invoke(locker);
       
   499         try {
       
   500             lockWaiter.
       
   501                     getTimeouts().
       
   502                     setTimeout("Waiter.WaitingTime",
       
   503                             timeouts.
       
   504                             getTimeout("QueueTool.LockTimeout"));
       
   505             lockWaiter.
       
   506                     getTimeouts().
       
   507                     setTimeout("Waiter.TimeDelta",
       
   508                             timeouts.
       
   509                             getTimeout("QueueTool.QueueCheckingDelta"));
       
   510             lockWaiter.waitAction(null);
       
   511         } catch (InterruptedException e) {
       
   512             output.printStackTrace(e);
       
   513         }
       
   514     }
       
   515 
       
   516     /**
       
   517      * Unlocks EventQueue.
       
   518      *
       
   519      * @see #lock()
       
   520      */
       
   521     public void unlock() {
       
   522         output.printTrace("Unlocking queue.");
       
   523         locker.setLocked(false);
       
   524     }
       
   525 
       
   526     /**
       
   527      * Locks event queue for "time" milliseconds. Returns immediately after
       
   528      * locking.
       
   529      *
       
   530      * @param time a time to lock the queue for.
       
   531      */
       
   532     public void lock(long time) {
       
   533         output.printTrace("Locking queue for " + Long.toString(time) + " milliseconds");
       
   534         lock();
       
   535         invoke(new UnlockPostponer(time));
       
   536     }
       
   537 
       
   538     /**
       
   539      * Sais if last locking was expired.
       
   540      *
       
   541      * @return true if last locking had beed expired.
       
   542      */
       
   543     public boolean wasLockingExpired() {
       
   544         return locker.expired;
       
   545     }
       
   546 
       
   547     /**
       
   548      * Action to be executed through event queue. Even if it was executed without
       
   549      * waiting by {@code invoke(QueueAction)} execution process can be
       
   550      * monitored by {@code getResult()}, {@code getException()},
       
   551      * {@code getFinished()} methods.
       
   552      */
       
   553     public static abstract class QueueAction<R> implements Runnable {
       
   554 
       
   555         private volatile boolean finished;
       
   556         private Exception exception;
       
   557         private R result;
       
   558         private String description;
       
   559 
       
   560         /**
       
   561          * Constructor.
       
   562          *
       
   563          * @param description a description.
       
   564          */
       
   565         public QueueAction(String description) {
       
   566             this.description = description;
       
   567             finished = false;
       
   568             exception = null;
       
   569             result = null;
       
   570         }
       
   571 
       
   572         /**
       
   573          * Method to implement action functionality.
       
   574          *
       
   575          * @return an Object - action result
       
   576          * @throws Exception
       
   577          */
       
   578         public abstract R launch()
       
   579                 throws Exception;
       
   580 
       
   581         /**
       
   582          */
       
   583         @Override
       
   584         public final void run() {
       
   585             finished = false;
       
   586             exception = null;
       
   587             result = null;
       
   588             try {
       
   589                 result = launch();
       
   590             } catch (Exception e) {
       
   591                 exception = e;
       
   592             } finally {
       
   593                 finished = true;
       
   594             }
       
   595         }
       
   596 
       
   597         /**
       
   598          * Action description.
       
   599          *
       
   600          * @return the description.
       
   601          */
       
   602         public String getDescription() {
       
   603             return description;
       
   604         }
       
   605 
       
   606         /**
       
   607          * Returns action result if action has already been finished, null
       
   608          * otherwise.
       
   609          *
       
   610          * @return an action result.
       
   611          */
       
   612         public R getResult() {
       
   613             return result;
       
   614         }
       
   615 
       
   616         /**
       
   617          * Returns exception occured during action execution (if any).
       
   618          *
       
   619          * @return the Exception happened inside {@code launch()} method.
       
   620          */
       
   621         public Exception getException() {
       
   622             return exception;
       
   623         }
       
   624 
       
   625         /**
       
   626          * Informs whether action has been finished or not.
       
   627          *
       
   628          * @return true if this action have been finished
       
   629          */
       
   630         public boolean getFinished() {
       
   631             return finished;
       
   632         }
       
   633 
       
   634         @Override
       
   635         public String toString() {
       
   636             return "QueueAction{description=" + description + ", result=" + result + ", finished=" + finished + ", exception=" + exception + '}';
       
   637         }
       
   638     }
       
   639 
       
   640     private static class JemmyQueue extends EventQueue {
       
   641 
       
   642         private boolean installed = false;
       
   643 
       
   644         public void shortcutEvent(AWTEvent event) {
       
   645             super.dispatchEvent(event);
       
   646         }
       
   647 
       
   648         @Override
       
   649         protected void dispatchEvent(AWTEvent event) {
       
   650             //it's necessary to catch exception here.
       
   651             //because test might already fail by timeout
       
   652             //but generated events are still in stack
       
   653             try {
       
   654                 super.dispatchEvent(event);
       
   655             } catch (Exception e) {
       
   656                 //the exceptions should be printed into
       
   657                 //Jemmy output - not System.out
       
   658                 JemmyProperties.getCurrentOutput().printStackTrace(e);
       
   659             }
       
   660         }
       
   661 
       
   662         public synchronized void install() {
       
   663             if (!installed) {
       
   664                 getQueue().push(this);
       
   665                 installed = true;
       
   666             }
       
   667         }
       
   668 
       
   669         public synchronized void uninstall() {
       
   670             if (installed) {
       
   671                 pop();
       
   672                 installed = false;
       
   673             }
       
   674         }
       
   675     }
       
   676 
       
   677     private class EventWaiter implements Runnable {
       
   678 
       
   679         boolean empty = true;
       
   680         long emptyTime;
       
   681 
       
   682         public EventWaiter(long emptyTime) {
       
   683             this.emptyTime = emptyTime;
       
   684         }
       
   685 
       
   686         @Override
       
   687         public void run() {
       
   688             long startTime = System.currentTimeMillis();
       
   689             while ((empty = checkEmpty())
       
   690                     && (System.currentTimeMillis() - startTime) < emptyTime) {
       
   691                 timeouts.sleep("QueueTool.QueueCheckingDelta");
       
   692             }
       
   693         }
       
   694     }
       
   695 
       
   696     private class StayingEmptyWaiter extends Waiter<String, Void> {
       
   697 
       
   698         long emptyTime;
       
   699 
       
   700         public StayingEmptyWaiter(long emptyTime) {
       
   701             this.emptyTime = emptyTime;
       
   702         }
       
   703 
       
   704         @Override
       
   705         public String actionProduced(Void obj) {
       
   706             try {
       
   707                 EventWaiter eventWaiter = new EventWaiter(emptyTime);
       
   708                 EventQueue.invokeAndWait(eventWaiter);
       
   709                 if (eventWaiter.empty
       
   710                         && timeFromStart() <= super.getTimeouts().getTimeout("Waiter.WaitingTime")) {
       
   711                     return "Reached";
       
   712                 }
       
   713             } catch (InterruptedException | InvocationTargetException e) {
       
   714                 output.printStackTrace(e);
       
   715             }
       
   716             return null;
       
   717         }
       
   718 
       
   719         @Override
       
   720         public String getDescription() {
       
   721             return "Wait event queue staying empty for " + emptyTime;
       
   722         }
       
   723 
       
   724         @Override
       
   725         public String toString() {
       
   726             return "StayingEmptyWaiter{" + "emptyTime=" + emptyTime + '}';
       
   727         }
       
   728     }
       
   729 
       
   730     private class ActionRunnable<R, P> extends QueueAction<R> {
       
   731 
       
   732         Action<R, P> action;
       
   733         P param;
       
   734 
       
   735         public ActionRunnable(Action<R, P> action, P param) {
       
   736             super(action.getDescription());
       
   737             this.action = action;
       
   738             this.param = param;
       
   739         }
       
   740 
       
   741         @Override
       
   742         public R launch() throws Exception {
       
   743             return action.launch(param);
       
   744         }
       
   745     }
       
   746 
       
   747     private class RunnableRunnable extends QueueAction<Void> {
       
   748 
       
   749         Runnable action;
       
   750 
       
   751         public RunnableRunnable(Runnable action) {
       
   752             super("Runnable");
       
   753             this.action = action;
       
   754         }
       
   755 
       
   756         @Override
       
   757         public Void launch() throws Exception {
       
   758             action.run();
       
   759             return null;
       
   760         }
       
   761     }
       
   762 
       
   763     private class Locker extends QueueAction<Void> {
       
   764 
       
   765         volatile boolean locked = false;
       
   766         long wholeTime, deltaTime;
       
   767         boolean expired;
       
   768 
       
   769         public Locker() {
       
   770             super("Event queue locking");
       
   771         }
       
   772 
       
   773         @Override
       
   774         public Void launch() {
       
   775             wholeTime = timeouts.getTimeout("QueueTool.MaximumLockingTime");
       
   776             deltaTime = timeouts.getTimeout("QueueTool.QueueCheckingDelta");
       
   777             setLocked(true);
       
   778             expired = false;
       
   779             long startTime = System.currentTimeMillis();
       
   780             while (isLocked()) {
       
   781                 try {
       
   782                     Thread.sleep(deltaTime);
       
   783                 } catch (InterruptedException e) {
       
   784                     getOutput().printStackTrace(e);
       
   785                 }
       
   786                 if (System.currentTimeMillis() - startTime > wholeTime) {
       
   787                     getOutput().printLine("Locking has been expired!");
       
   788                     expired = true;
       
   789                     break;
       
   790                 }
       
   791             }
       
   792             return null;
       
   793         }
       
   794 
       
   795         public void setLocked(boolean locked) {
       
   796             this.locked = locked;
       
   797         }
       
   798 
       
   799         public boolean isLocked() {
       
   800             return locked;
       
   801         }
       
   802     }
       
   803 
       
   804     private class UnlockPostponer implements Runnable {
       
   805 
       
   806         long time;
       
   807 
       
   808         public UnlockPostponer(long time) {
       
   809             this.time = time;
       
   810         }
       
   811 
       
   812         @Override
       
   813         public void run() {
       
   814             new Timeout("", time).sleep();
       
   815             unlock();
       
   816         }
       
   817     }
       
   818 }