1 /*
   2  * Copyright (c) 2007, 2017 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. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package org.jemmy.action;
  26 
  27 import org.jemmy.env.Environment;
  28 import org.jemmy.env.TestOut;
  29 import org.jemmy.env.Timeout;
  30 import org.jemmy.timing.State;
  31 import org.jemmy.timing.Waiter;
  32 
  33 /**
  34  *
  35  * @author shura
  36  */
  37 public abstract class AbstractExecutor implements ActionExecutor {
  38 
  39     /**
  40      * Default timeout for action {@linkplain Action#run(java.lang.Object[])
  41      * run()} method to be completed.
  42      */
  43     public static final Timeout MAX_ACTION_TIME = new Timeout("max.action.time", 60000);
  44     /**
  45      * Indentifies output which would be used to print information for all actions
  46      * executed not on event queue.
  47      * @see AbstractExecutor#execute(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[])
  48      * @see AbstractExecutor#executeDetached(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[])
  49      * @see Environment#getOutput(java.lang.String)
  50      */
  51     public static final String NON_QUEUE_ACTION_OUTPUT = "org.jemmy.action.AbstractExecutor.NON_QUEUE_ACTION_OUTPUT";
  52     /**
  53      * Indentifies output which would be used to print information for all actions
  54      * executed on event queue.
  55      * @see AbstractExecutor#execute(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[])
  56      * @see AbstractExecutor#executeDetached(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[])
  57      * @see Environment#getOutput(java.lang.String)
  58      */
  59     public static final String QUEUE_ACTION_OUTPUT = "org.jemmy.action.AbstractExecutor.QUEUE_ACTION_OUTPUT";
  60     private ActionQueue queue;
  61 
  62     /**
  63      *
  64      */
  65     public AbstractExecutor() {
  66         queue = new ActionQueue();
  67     }
  68 
  69     static {
  70         Environment.getEnvironment().initTimeout(MAX_ACTION_TIME);
  71         Environment.getEnvironment().initOutput(QUEUE_ACTION_OUTPUT, TestOut.getNullOutput());
  72         Environment.getEnvironment().initOutput(NON_QUEUE_ACTION_OUTPUT, TestOut.getNullOutput());
  73     }
  74 
  75     /**
  76      *
  77      * @return
  78      */
  79     protected int actionsInQueue() {
  80         return queue.actionsInQueue();
  81     }
  82 
  83     /**
  84      * {@inheritDoc }
  85      * Prints out what action is executed into output
  86      * specified by either NON_QUEUE_ACTION_OUTPUT or QUEUE_ACTION_OUTPUT
  87      * depending whether the action is called on queue or not. No output provided for
  88      * nested actions - only the top level ones are printed.
  89      * @see TestOut#getOutput(java.lang.String)
  90      */
  91     public final void execute(Environment env, boolean dispatch, final Action action, Object... parameters) {
  92         printStrace(env, "Action: ", action);
  93         action.setAllowedTime(env.getTimeout(MAX_ACTION_TIME.getName()).getValue());
  94         if (dispatch) {
  95             executeQueue(env, action, parameters);
  96         } else {
  97             if (isInAction()) {
  98                 action.execute(parameters);
  99             } else {
 100                 queue.invokeAndWait(action, parameters);
 101             }
 102         }
 103     }
 104 
 105     /**
 106      * {@inheritDoc }
 107      * Prints out what action is executed into output
 108      * specified by either NON_QUEUE_ACTION_OUTPUT or QUEUE_ACTION_OUTPUT
 109      * depending whether the action is called on queue or not. No output provided for
 110      * nested actions - only the top level ones are printed.
 111      * @see TestOut#getOutput(java.lang.String)
 112      */
 113     public final void executeDetached(Environment env, boolean dispatch, final Action action, final Object... parameters) {
 114         printStrace(env, "Action detached: ", action);
 115         if (dispatch) {
 116             executeQueueDetached(env, action, parameters);
 117         } else {
 118             if (isInAction()) {
 119                 new Thread(new Runnable() {
 120 
 121                     public void run() {
 122                         action.execute(parameters);
 123                     }
 124                 }).start();
 125             } else {
 126                 queue.invoke(action, parameters);
 127             }
 128         }
 129     }
 130 
 131     private void printStrace(Environment env, String text, Action action) {
 132         String toString = action.toString();
 133         if (toString != null && toString.length() > 0) {
 134             if (!isInAction()) {
 135                 if (isOnQueue()) {
 136                     env.getOutput(QUEUE_ACTION_OUTPUT).println(text + action.toString());
 137                 } else {
 138                     env.getOutput(NON_QUEUE_ACTION_OUTPUT).println(text + action.toString());
 139                 }
 140             }
 141         }
 142     }
 143 
 144     /**
 145      * {@inheritDoc}
 146      */
 147     public final boolean isInAction() {
 148         return queue.getQueueThread() == Thread.currentThread() || isOnQueue();
 149     }
 150 
 151     /**
 152      * Schedules to execute an action through the UI system's dispatch thread and
 153      * waits for the action to be completed. This method is called from
 154      * {@linkplain #execute(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[]) execute()}
 155      * method when it is invoked with dispatch argument set to true.
 156      * @param env Environment.
 157      * @param action action to execute.
 158      * @param parameters parameters to pass to {@linkplain Action#run(java.lang.Object[]) action.run()} method.
 159      */
 160     public abstract void executeQueue(Environment env, Action action, Object... parameters);
 161 
 162     /**
 163      * Schedules to execute an action through the UI system's dispatch thread and
 164      * exits immediately. This method is called from
 165      * {@linkplain #executeDetached(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[]) executeDetached()}
 166      * method when it is invoked with dispatch argument set to true.
 167      * @param env Environment.
 168      * @param action action to execute.
 169      * @param parameters parameters to pass to {@linkplain Action#run(java.lang.Object[]) action.run()} method.
 170      */
 171     public abstract void executeQueueDetached(Environment env, Action action, Object... parameters);
 172 
 173     /**
 174      * Checks whether this is invoked from the UI system event queue.
 175      * @return true if invoked from the UI system event queue.
 176      */
 177     public abstract boolean isOnQueue();
 178 
 179     /**
 180      * Waits for UI to became quiet which is determined using
 181      * {@linkplain #isQuiet() isQuiet()} method.
 182      * @param waitTime maximum time for waiting.
 183      */
 184     public void waitQuiet(Timeout waitTime) {
 185         new Waiter(waitTime).ensureState(new State<Object>() {
 186 
 187             public Object reached() {
 188                 return isQuiet() ? true : null;
 189             }
 190         });
 191     }
 192 
 193     /**
 194      * Tells whether the UI is quiet which usually means that all scheduled
 195      * actions are dispatched and the queue is empty.
 196      * @see #waitQuiet(org.jemmy.env.Timeout)
 197      * @return true if the UI is quiet.
 198      */
 199     protected abstract boolean isQuiet();
 200 }