Package org.netbeans.jemmy

Source Code of org.netbeans.jemmy.QueueTool$JemmyQueue

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License.  When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s): Alexandre Iline.
*
* The Original Software is the Jemmy library.
* The Initial Developer of the Original Software is Alexandre Iline.
* All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*
*
*
* $Id$ $Revision$ $Date$
*
*/

package org.netbeans.jemmy;

import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.awt.Toolkit;

import java.awt.event.InvocationEvent;

import java.util.Hashtable;

import java.lang.reflect.InvocationTargetException;

/**
*
* Provides functionality to work with java.awt.EventQueue empty.
*
* <BR><BR>Timeouts used: <BR>
* QueueTool.WaitQueueEmptyTimeout - timeout to wait queue emptied<BR>
* QueueTool.QueueCheckingDelta - time delta to check result<BR>
* QueueTool.LockTimeout - time to wait queue locked after lock action has been put there<BR>
* QueueTool.InvocationTimeout - time for action was put into queue to be started<BR>
* QueueTool.MaximumLockingTime - maximum time to lock queue.<br>
*
* @see Timeouts
*
* @author Alexandre Iline (alexandre.iline@sun.com)
*
*/
public class QueueTool implements Outputable, Timeoutable {

    private final static long WAIT_QUEUE_EMPTY_TIMEOUT = 180000;
    private final static long QUEUE_CHECKING_DELTA = 10;
    private final static long LOCK_TIMEOUT = 180000;
    private final static long MAXIMUM_LOCKING_TIME = 180000;
    private final static long INVOCATION_TIMEOUT = 180000;

    private static JemmyQueue jemmyQueue = null;

    private TestOut output;
    private Timeouts timeouts;
    private Locker locker;
    private Waiter lockWaiter;

    /**
     * Constructor.
     */
    public QueueTool() {
  locker = new Locker();
  lockWaiter = new Waiter(new Waitable() {
    public Object actionProduced(Object obj) {
        return(locker.isLocked() ? "" : null);
    }
    public String getDescription() {
        return("Event queue to be locked");
    }
      });
  setOutput(JemmyProperties.getProperties().getOutput());
  setTimeouts(JemmyProperties.getProperties().getTimeouts());
    }

    /**
     * Returns system EventQueue.
     * @return system EventQueue.
     */
    public static EventQueue getQueue() {
        return(Toolkit.getDefaultToolkit().getSystemEventQueue());
    }

    /**
     * Map to <code>EventQueue.isDispatchThread()</code>.
     * @return true if this thread is the AWT dispatching thread.
     */
    public static boolean isDispatchThread() {
  return(getQueue().isDispatchThread());
    }

    /**
     * Checks if system event queue is empty.
     * @return true if EventQueue is empty.
     */
    public static boolean checkEmpty() {
  return(getQueue().peekEvent() == null);
    }

    /**
     * Shortcuts event if
     * <code>((JemmyProperties.getCurrentDispatchingModel() & JemmyProperties.SHORTCUT_MODEL_MASK) != 0)</code>
     * and if executed in the dispatch thread.
     * Otherwise posts event.
     * @param event Event to dispatch.
     */
    public static void processEvent(AWTEvent event) {
        if((JemmyProperties.getCurrentDispatchingModel() &
            JemmyProperties.SHORTCUT_MODEL_MASK) != 0) {
            installQueue();
        }   
        if((JemmyProperties.getCurrentDispatchingModel() &
            JemmyProperties.SHORTCUT_MODEL_MASK) != 0 &&
           isDispatchThread()) {
            shortcutEvent(event);
        } else {
            postEvent(event);
        }
    }

    /**
     * Simply posts events into the system event queue.
     * @param event Event to dispatch.
     */
    public static void postEvent(AWTEvent event) {
        getQueue().postEvent(event);
    }

    /**
     * Dispatches event ahead of all events staying in the event queue.
     * @param event an event to be shortcut.
     */
    public static void shortcutEvent(AWTEvent event) {
        installQueue();
        jemmyQueue.shortcutEvent(event);
    }

    /**
     * Installs own Jemmy EventQueue implementation.
     * The method is executed in dispatchmode only.
     * @see #uninstallQueue
     */
    public static void installQueue() {
        if(jemmyQueue == null) {
            jemmyQueue = new JemmyQueue();
        }
        jemmyQueue.install();
    }

    /**
     * Uninstalls own Jemmy EventQueue implementation.
     * @see #installQueue
     */
    public static void uninstallQueue() {
        if(jemmyQueue != null) {
            jemmyQueue.uninstall();
        }
    }

    static {
  Timeouts.initDefault("QueueTool.WaitQueueEmptyTimeout", WAIT_QUEUE_EMPTY_TIMEOUT);
  Timeouts.initDefault("QueueTool.QueueCheckingDelta", QUEUE_CHECKING_DELTA);
  Timeouts.initDefault("QueueTool.LockTimeout", LOCK_TIMEOUT);
  Timeouts.initDefault("QueueTool.InvocationTimeout", INVOCATION_TIMEOUT);
  Timeouts.initDefault("QueueTool.MaximumLockingTime", MAXIMUM_LOCKING_TIME);
    }

    /**
     * Defines current timeouts.
     *
     * @param  ts ?t? A collection of timeout assignments.
     * @see  org.netbeans.jemmy.Timeouts
     * @see  org.netbeans.jemmy.Timeoutable
     * @see #getTimeouts
     */
    public void setTimeouts(Timeouts ts) {
  timeouts = ts;
  lockWaiter.setTimeouts(getTimeouts().cloneThis());
    }

    /**
     * Return current timeouts.
     * @return the collection of current timeout assignments.
     * @see org.netbeans.jemmy.Timeouts
     * @see org.netbeans.jemmy.Timeoutable
     * @see #setTimeouts
     */
    public Timeouts getTimeouts() {
  return(timeouts);
    }

    /**
     * Defines print output streams or writers.
     * @param out Identify the streams or writers used for print output.
     * @see org.netbeans.jemmy.Outputable
     * @see org.netbeans.jemmy.TestOut
     * @see #getOutput
     */
    public void setOutput(TestOut out) {
  output = out;
  lockWaiter.setOutput(output.createErrorOutput());
    }

    /**
     * Returns print output streams or writers.
     * @return an object that contains references to objects for
     * printing to output and err streams.
     * @see org.netbeans.jemmy.Outputable
     * @see org.netbeans.jemmy.TestOut
     * @see #setOutput
     */
    public TestOut getOutput() {
  return(output);
    }

    /**
     * Waits for system event queue empty.
     * Uses "QueueTool.WaitQueueEmptyTimeout" milliseconds to wait.
     * @throws TimeoutExpiredException
     */
    public void waitEmpty() {
  Waiter waiter = new Waiter(new Waitable() {
      public Object actionProduced(Object obj) {
    if(checkEmpty()) {
        return("Empty");
    }
    return(null);
      }
      public String getDescription() {
    return("Wait event queue empty");
      }
  });
  waiter.setTimeouts(timeouts.cloneThis());
  waiter.getTimeouts().setTimeout("Waiter.WaitingTime",
          timeouts.getTimeout("QueueTool.WaitQueueEmptyTimeout"));
  waiter.setOutput(output);
  try {
      waiter.waitAction(null);
  } catch(TimeoutExpiredException e) {
            final AWTEvent event = getQueue().peekEvent();
            // if event != null run toString in dispatch thread
            String eventToString = (event == null) ? "null" : (String)invokeSmoothly(
                new QueueTool.QueueAction("event.toString()") {
                    public Object launch() {
                        return event.toString();
                    }
                }
            );
            getOutput().printErrLine("Event at the top of stack: " + eventToString);
            throw(e);
  } catch(InterruptedException e) {
      output.printStackTrace(e);
  }
    }

    /**
     * Waits for system event queue be empty for <code>emptyTime</code> milliseconds.
     * Uses "QueueTool.WaitQueueEmptyTimeout" milliseconds to wait.
     *
     * @throws  TimeoutExpiredException
     * @param  emptyTime time for the queue to stay empty.
     */
    public void waitEmpty(long emptyTime) {

  StayingEmptyWaiter waiter = new StayingEmptyWaiter(emptyTime);
  waiter.setTimeouts(timeouts.cloneThis());
  waiter.getTimeouts().setTimeout("Waiter.WaitingTime",
          timeouts.getTimeout("QueueTool.WaitQueueEmptyTimeout"));
  waiter.setOutput(output);
  try {
      waiter.waitAction(null);
  } catch(TimeoutExpiredException e) {
            final AWTEvent event = getQueue().peekEvent();
            String eventToString = (event == null) ? "null" : (String)invokeSmoothly(
            new QueueTool.QueueAction("event.toString()") {
                public Object launch() {
                    return event.toString();
                }
            }
            );
            getOutput().printErrLine("Event at the top of stack: " + eventToString);
            throw(e);
  } catch(InterruptedException e) {
      output.printStackTrace(e);
  }
    }

    /**
     * Invokes action through EventQueue.
     * Does not wait for it execution.
     * @param action an action to be invoked.
     */
    public void invoke(QueueAction action) {
  output.printTrace("Invoking \"" + action.getDescription() + "\" action through event queue");
  EventQueue.invokeLater(action);
    }

    /**
     * Invokes runnable through EventQueue.
     * Does not wait for it execution.
     * @param  runnable a runnable to be invoked.
     * @return  QueueAction instance which can be use for execution monitoring.
     * @see  QueueTool.QueueAction
     */
    public QueueAction invoke(Runnable runnable) {
  QueueAction result = new RunnableRunnable(runnable);
  invoke(result);
  return(result);
    }

    /**
     * Invokes action through EventQueue.
     * Does not wait for it execution.
     * @param action an action to be invoked.
     * @param param <code>action.launch(Object)</code> method parameter.
     * @return QueueAction instance which can be use for execution monitoring.
     * @see QueueTool.QueueAction
     */
    public QueueAction invoke(Action action, Object param) {
  QueueAction result = new ActionRunnable(action, param);
  invoke(result);
  return(result);
    }

    /**
     * Being executed outside of AWT dispatching thread,
     * invokes an action through the event queue.
     * Otherwise executes <code>action.launch()</code> method
     * directly.
     * @param action anaction to be executed.
     * @return Action result.
     */
    public Object invokeSmoothly(QueueAction action) {
        if(!getQueue().isDispatchThread()) {
            return(invokeAndWait(action));
        } else {
            try {
                return(action.launch());
            } catch(Exception e) {
                throw(new JemmyException("Exception in " + action.getDescription(), e));
            }
        }
    }

    /**
     * Being executed outside of AWT dispatching thread,
     * invokes a runnable through the event queue.
     * Otherwise executes <code>runnable.run()</code> method
     * directly.
     * @param runnable a runnable to be executed.
     */
    public void invokeSmoothly(Runnable runnable) {
        if(!getQueue().isDispatchThread()) {
            invokeAndWait(runnable);
        } else {
            runnable.run();
        }
    }

    /**
     * Being executed outside of AWT dispatching thread,
     * invokes an action through the event queue.
     * Otherwise executes <code>action.launch(Object)</code> method
     * directly.
     * @param action anaction to be executed.
     * @param param an action parameter
     * @return Action result.
     */
    public Object invokeSmoothly(Action action, Object param) {
        if(!getQueue().isDispatchThread()) {
            return(invokeAndWait(action, param));
        } else {
            return(action.launch(param));
        }
    }

    /**
     * Invokes action through EventQueue.
     * Waits for it execution.
     * @param action an action to be invoked.
     * @return a result of action
     * @throws TimeoutExpiredException if action
     * was not executed in "QueueTool.InvocationTimeout" milliseconds.
     */
    public Object invokeAndWait(QueueAction action) {
 
        class JemmyInvocationLock {}
        Object lock = new JemmyInvocationLock();
        InvocationEvent event =
            new InvocationEvent(Toolkit.getDefaultToolkit(),
                                action,
                                lock,
        true);
  try {
            synchronized (lock) {
                getQueue().postEvent(event);
                lock.wait();
            }
  } catch(InterruptedException e) {
      throw(new JemmyException("InterruptedException during " +
             action.getDescription() +
             " execution", e));
  }
  if(action.getException() != null) {
      throw(new JemmyException("Exception in " + action.getDescription(),
             action.getException()));
  }
  if(event.getException() != null) {
      throw(new JemmyException("Exception in " + action.getDescription(),
             event.getException()));
  }
  return(action.getResult());
    }

    /**
     * Invokes runnable through EventQueue.
     * Waits for it execution.
     * @param runnable a runnable to be invoked.
     * @throws  TimeoutExpiredException if runnable
     * was not executed in "QueueTool.InvocationTimeout" milliseconds.
     */
    public void invokeAndWait(Runnable runnable) {
  invokeAndWait(new RunnableRunnable(runnable));
    }

    /**
     * Invokes action through EventQueue.
     * Waits for it execution.
     * May throw TimeoutExpiredException if action
     * was not executed in "QueueTool.InvocationTimeout" milliseconds.
     * @param action an action to be invoked.
     * @param  param action.launch(Object method parameter.
     * @return a result of action
     * @throws  TimeoutExpiredException if action
     * was not executed in "QueueTool.InvocationTimeout" milliseconds.
     */
    public Object invokeAndWait(Action action, Object param) {
  return(invokeAndWait(new ActionRunnable(action, param)));
    }

    /**
     * Locks EventQueue.
     * Locking will be automatically aborted after
     * "QueueTool.MaximumLockingTime" milliseconds.
     * @see #unlock()
     * @throws TimeoutExpiredException
     */
    public void lock() {
  output.printTrace("Locking queue.");
  invoke(locker);
  try {
      lockWaiter.
    getTimeouts().
    setTimeout("Waiter.WaitingTime",
         timeouts.
         getTimeout("QueueTool.LockTimeout"));
      lockWaiter.
    getTimeouts().
    setTimeout("Waiter.TimeDelta",
         timeouts.
         getTimeout("QueueTool.QueueCheckingDelta"));
      lockWaiter.waitAction(null);
  } catch(InterruptedException e) {
      output.printStackTrace(e);
  }
    }

    /**
     * Unlocks EventQueue.
     * @see #lock()
     */
    public void unlock() {
  output.printTrace("Unlocking queue.");
  locker.setLocked(false);
    }

    /**
     * Locks event queue for "time" milliseconds.
     * Returns immediately after locking.
     * @param  time a time to lock the queue for.
     */
    public void lock(long time) {
  output.printTrace("Locking queue for " + Long.toString(time) + " milliseconds");
  lock();
  invoke(new UnlockPostponer(time));
    }

    /**
     * Sais if last locking was expired.
     * @return true if last locking had beed expired.
     */
    public boolean wasLockingExpired() {
  return(locker.expired);
    }

    /**
     * Action to be excuted through event queue.
     * Even if it was executed without waiting by <code>invoke(QueueAction)</code>
     * execution process can be monitored by <code>getResult()</code>,
     * <code>getException()</code>, <code>getFinished()</code> methods.
     */
    public static abstract class QueueAction implements Runnable {
  private boolean finished;
  private Exception exception;
  private Object result;
  private String description;
  /**
   * Constructor.
         * @param description a description.
   */
  public QueueAction(String description) {
      this.description = description;
      finished = false;
      exception = null;
      result = null;
        }
  /**
   * Method to implement action functionality.
         * @return an Object - action result
         * @throws Exception
   */
  public abstract Object launch()
      throws Exception;

  /**
   */
  public final void run() {
      finished = false;
      exception = null;
      result = null;
      try {
    result = launch();
      } catch(Exception e) {
    exception = e;
      }
      finished = true;
  }
  /**
   * Action description.
         * @return the description.
   */
  public String getDescription() {
      return(description);
  }
  /**
   * Returns action result if action has already been finished,
   * null otherwise.
         * @return an action result.
   */
  public Object getResult() {
      return(result);
  }
  /**
   * Returns exception occured during action execution (if any).
         * @return the Exception happened inside <code>launch()</code> method.
   */
  public Exception getException() {
      return(exception);
  }
  /**
   * Informs whether action has been finished or not.
         * @return true if this action have been finished
   */
  public boolean getFinished() {
      return(finished);
  }
    }

    private static class JemmyQueue extends EventQueue {
        private boolean installed = false;
        public void shortcutEvent(AWTEvent event) {
            super.dispatchEvent(event);
        }
        protected void dispatchEvent(AWTEvent event) {
            //it's necessary to catch exception here.
            //because test might already fail by timeout
            //but generated events are still in stack
            try {
                super.dispatchEvent(event);
            } catch(Exception e) {
                //the exceptions should be printed into
                //Jemmy output - not System.out
                JemmyProperties.getCurrentOutput().printStackTrace(e);
            }
        }
        public synchronized void install() {
            if(!installed) {
                getQueue().push(this);
                installed = true;
            }
        }
        public synchronized void uninstall() {
            if(installed) {
                pop();
                installed = false;
            }
        }
    }

    private class EventWaiter implements Runnable {
  boolean empty = true;
  long emptyTime;
  public EventWaiter(long emptyTime) {
      this.emptyTime = emptyTime;
  }
  public void run() {
      long startTime = System.currentTimeMillis();
      while((empty = checkEmpty()) &&
      (System.currentTimeMillis() - startTime) < emptyTime) {
    timeouts.sleep("QueueTool.QueueCheckingDelta");
      }
  }
    }

    private class StayingEmptyWaiter extends Waiter {
  long emptyTime;

  public StayingEmptyWaiter(long emptyTime) {
      this.emptyTime = emptyTime;
  }

  public Object actionProduced(Object obj) {
      try {
    EventWaiter eventWaiter = new EventWaiter(emptyTime);
    EventQueue.invokeAndWait(eventWaiter);
    if(eventWaiter.empty &&
       timeFromStart() <= super.getTimeouts().getTimeout("Waiter.WaitingTime")) {
        return("Reached");
    }
      } catch(InterruptedException e) {
    output.printStackTrace(e);
      } catch(InvocationTargetException e) {
    output.printStackTrace(e);
      }
      return(null);
  }
  public String getDescription() {
      return("Wait event queue staying empty for " +
       Long.toString(emptyTime));
  }
    }

    private class ActionRunnable extends QueueAction {
  Action action;
  Object param;
  public ActionRunnable(Action action, Object param) {
      super(action.getDescription());
      this.action = action;
      this.param = param;
  }
  public Object launch() throws Exception {
      return(action.launch(param));
  }
    }

    private class RunnableRunnable extends QueueAction {
  Runnable action;
  public RunnableRunnable(Runnable action) {
      super("Runnable");
      this.action = action;
  }
  public Object launch() throws Exception {
      action.run();
      return(null);
  }
    }

    private class Locker extends QueueAction {
  boolean locked = false;
  long wholeTime, deltaTime;
  boolean expired;
  public Locker() {
      super("Event queue locking");
  }
  public Object launch() {
      wholeTime = timeouts.getTimeout("QueueTool.MaximumLockingTime");
      deltaTime = timeouts.getTimeout("QueueTool.QueueCheckingDelta");
      setLocked(true);
      expired = false;
      long startTime = System.currentTimeMillis();
      while(isLocked()) {
    try {
        Thread.sleep(deltaTime);
    } catch(InterruptedException e) {
        getOutput().printStackTrace(e);
    }
    if(System.currentTimeMillis() - startTime > wholeTime) {
        getOutput().printLine("Locking has been expired!");
        expired = true;
        break;
    }
      }
      return(null);
  }
  public void setLocked(boolean locked) {
      this.locked = locked;
  }
  public boolean isLocked() {
      return(locked);
  }
    }

    private class UnlockPostponer implements Runnable {
  long time;
  public UnlockPostponer(long time) {
      this.time = time;
  }
  public void run() {
      new Timeout("", time).sleep();
      unlock();
  }
    }
}
TOP

Related Classes of org.netbeans.jemmy.QueueTool$JemmyQueue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.