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.
   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.jemmy.action;
  24 
  25 import org.jemmy.env.Environment;
  26 import org.jemmy.env.TestOut;
  27 import org.jemmy.env.Timeout;
  28 import org.jemmy.timing.State;
  29 import org.jemmy.timing.Waiter;
  30 
  31 /**
  32  *
  33  * @author shura
  34  */
  35 public abstract class AbstractExecutor implements ActionExecutor {
  36 
  37     /**
  38      * Default timeout for action {@linkplain Action#run(java.lang.Object[])
  39      * run()} method to be completed.
  40      */
  41     public static final Timeout MAX_ACTION_TIME = new Timeout("max.action.time", 60000);
  42     /**
  43      * Indentifies output which would be used to print information for all actions
  44      * executed not on event queue.
  45      * @see AbstractExecutor#execute(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[])
  46      * @see AbstractExecutor#executeDetached(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[])
  47      * @see Environment#getOutput(java.lang.String)
  48      */
  49     public static final String NON_QUEUE_ACTION_OUTPUT = "org.jemmy.action.AbstractExecutor.NON_QUEUE_ACTION_OUTPUT";
  50     /**
  51      * Indentifies output which would be used to print information for all actions
  52      * executed on event queue.
  53      * @see AbstractExecutor#execute(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[])
  54      * @see AbstractExecutor#executeDetached(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[])
  55      * @see Environment#getOutput(java.lang.String)
  56      */
  57     public static final String QUEUE_ACTION_OUTPUT = "org.jemmy.action.AbstractExecutor.QUEUE_ACTION_OUTPUT";
  58     private ActionQueue queue;
  59 
  60     /**
  61      *
  62      */
  63     public AbstractExecutor() {
  64         queue = new ActionQueue();
  65     }
  66 
  67     static {
  68         Environment.getEnvironment().initTimeout(MAX_ACTION_TIME);
  69         Environment.getEnvironment().initOutput(QUEUE_ACTION_OUTPUT, TestOut.getNullOutput());
  70         Environment.getEnvironment().initOutput(NON_QUEUE_ACTION_OUTPUT, TestOut.getNullOutput());
  71     }
  72 
  73     /**
  74      * 
  75      * @return
  76      */
  77     protected int actionsInQueue() {
  78         return queue.actionsInQueue();
  79     }
  80 
  81     /**
  82      * {@inheritDoc }
  83      * Prints out what action is executed into output
  84      * specified by either NON_QUEUE_ACTION_OUTPUT or QUEUE_ACTION_OUTPUT
  85      * depending whether the action is called on queue or not. No output provided for
  86      * nested actions - only the top level ones are printed.
  87      * @see TestOut#getOutput(java.lang.String)
  88      */
  89     public final void execute(Environment env, boolean dispatch, final Action action, Object... parameters) {
  90         printStrace(env, "Action: ", action);
  91         action.setAllowedTime(env.getTimeout(MAX_ACTION_TIME.getName()).getValue());
  92         if (dispatch) {
  93             executeQueue(env, action, parameters);
  94         } else {
  95             if (isInAction()) {
  96                 action.execute(parameters);
  97             } else {
  98                 queue.invokeAndWait(action, parameters);
  99             }
 100         }
 101     }
 102 
 103     /**
 104      * {@inheritDoc }
 105      * Prints out what action is executed into output
 106      * specified by either NON_QUEUE_ACTION_OUTPUT or QUEUE_ACTION_OUTPUT
 107      * depending whether the action is called on queue or not. No output provided for
 108      * nested actions - only the top level ones are printed.
 109      * @see TestOut#getOutput(java.lang.String)
 110      */
 111     public final void executeDetached(Environment env, boolean dispatch, final Action action, final Object... parameters) {
 112         printStrace(env, "Action detached: ", action);
 113         if (dispatch) {
 114             executeQueueDetached(env, action, parameters);
 115         } else {
 116             if (isInAction()) {
 117                 new Thread(new Runnable() {
 118 
 119                     public void run() {
 120                         action.execute(parameters);
 121                     }
 122                 }).start();
 123             } else {
 124                 queue.invoke(action, parameters);
 125             }
 126         }
 127     }
 128 
 129     private void printStrace(Environment env, String text, Action action) {
 130         String toString = action.toString();
 131         if (toString != null && toString.length() > 0) {
 132             if (!isInAction()) {
 133                 if (isOnQueue()) {
 134                     env.getOutput(QUEUE_ACTION_OUTPUT).println(text + action.toString());
 135                 } else {
 136                     env.getOutput(NON_QUEUE_ACTION_OUTPUT).println(text + action.toString());
 137                 }
 138             }
 139         }
 140     }
 141 
 142     /**
 143      * {@inheritDoc}
 144      */
 145     public final boolean isInAction() {
 146         return queue.getQueueThread() == Thread.currentThread() || isOnQueue();
 147     }
 148 
 149     /**
 150      * Schedules to execute an action through the UI system's dispatch thread and
 151      * waits for the action to be completed. This method is called from 
 152      * {@linkplain #execute(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[]) execute()}
 153      * method when it is invoked with dispatch argument set to true.
 154      * @param env Environment.
 155      * @param action action to execute.
 156      * @param parameters parameters to pass to {@linkplain Action#run(java.lang.Object[]) action.run()} method.
 157      */
 158     public abstract void executeQueue(Environment env, Action action, Object... parameters);
 159 
 160     /**
 161      * Schedules to execute an action through the UI system's dispatch thread and
 162      * exits immediately. This method is called from 
 163      * {@linkplain #executeDetached(org.jemmy.env.Environment, boolean, org.jemmy.action.Action, java.lang.Object[]) executeDetached()}
 164      * method when it is invoked with dispatch argument set to true.
 165      * @param env Environment.
 166      * @param action action to execute.
 167      * @param parameters parameters to pass to {@linkplain Action#run(java.lang.Object[]) action.run()} method.
 168      */
 169     public abstract void executeQueueDetached(Environment env, Action action, Object... parameters);
 170 
 171     /**
 172      * Checks whether this is invoked from the UI system event queue.
 173      * @return true if invoked from the UI system event queue.
 174      */
 175     public abstract boolean isOnQueue();
 176 
 177     /**
 178      * Waits for UI to became quiet which is determined using
 179      * {@linkplain #isQuiet() isQuiet()} method.
 180      * @param waitTime maximum time for waiting.
 181      */
 182     public void waitQuiet(Timeout waitTime) {
 183         new Waiter(waitTime).ensureState(new State<Object>() {
 184 
 185             public Object reached() {
 186                 return isQuiet() ? true : null;
 187             }
 188         });
 189     }
 190 
 191     /**
 192      * Tells whether the UI is quiet which usually means that all scheduled
 193      * actions are dispatched and the queue is empty.
 194      * @see #waitQuiet(org.jemmy.env.Timeout) 
 195      * @return true if the UI is quiet.
 196      */
 197     protected abstract boolean isQuiet();
 198 }