1 /* 2 * Copyright (c) 2009, 2012, 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.fx; 26 27 import com.sun.javafx.tk.Toolkit; 28 import javafx.application.Platform; 29 import org.jemmy.JemmyException; 30 import org.jemmy.TimeoutExpiredException; 31 import org.jemmy.action.AbstractExecutor; 32 import org.jemmy.action.Action; 33 import org.jemmy.env.Environment; 34 import org.jemmy.env.Timeout; 35 import org.jemmy.timing.State; 36 37 /** 38 * A utility class to work with Java FX event queue. 39 * @author shura, KAM 40 */ 41 public class QueueExecutor extends AbstractExecutor { 42 43 /** 44 * @see #isQuiet() 45 */ 46 public static final Timeout QUEUE_THROUGH_TIME = new Timeout("FXExecutor.FX_QUEUE_THROUGH_TIME", 50); 47 static final Timeout QUEUE_IDENTIFYING_TIMEOUT = 48 new Timeout("jemmyfx.executor.queue.thread", 1000); 49 /** 50 * 51 */ 52 public static final QueueExecutor EXECUTOR = new QueueExecutor(); 53 Thread queueThread = null; 54 EmptyFunction emptyFunction; 55 56 private QueueExecutor() { 57 super(); 58 emptyFunction = new EmptyFunction(); 59 } 60 61 /** 62 * Gets what thread is the queue thread. 63 * @return 64 */ 65 public Thread getQueueThread() { 66 if (queueThread == null) { 67 try { 68 Platform.runLater(new Runnable() { 69 70 @Override 71 public void run() { 72 queueThread = Thread.currentThread(); 73 } 74 }); 75 Root.ROOT.getEnvironment().getWaiter(QUEUE_IDENTIFYING_TIMEOUT.getName()).ensureState(new State<Object>() { 76 77 @Override 78 public Object reached() { 79 return queueThread; 80 } 81 }); 82 } catch (TimeoutExpiredException e) { 83 //this is bad. THere got to be a way to check if we're on the queue 84 //or not. right now - no other way - sorry 85 queueThread = Thread.currentThread(); 86 } 87 } 88 return queueThread; 89 } 90 91 /** 92 * {@inheritDoc} 93 * @param env 94 * @param action 95 * @param parameters 96 */ 97 @Override 98 public void executeQueue(Environment env, Action action, Object... parameters) { 99 if (isOnQueue()) { 100 action.execute(parameters); 101 } else { 102 final WrapperFunction wrapper = new WrapperFunction(); 103 wrapper.setAction(action); 104 wrapper.setParameters(parameters); 105 Platform.runLater(wrapper); 106 wrapper.waitDone(env.getTimeout(MAX_ACTION_TIME)); 107 if (wrapper.failed()) { 108 throw new JemmyException("Failed to execute action '" + action + "' through Platform.runLater", action.getThrowable()); 109 } 110 } 111 } 112 113 /** 114 * {@inheritDoc} 115 * @param env 116 * @param action 117 * @param parameters 118 */ 119 @Override 120 public void executeQueueDetached(Environment env, Action action, Object... parameters) { 121 WrapperFunction w = new WrapperFunction(); 122 w.setAction(action); 123 w.setParameters(parameters); 124 Platform.runLater(w); 125 } 126 127 /** 128 * Checks whether the calling code is already on the queue thread. 129 * @return 130 */ 131 @Override 132 public boolean isOnQueue() { 133 //return Thread.currentThread().equals(getQueueThread()); 134 try { 135 Toolkit.getToolkit().checkFxUserThread(); 136 } catch (Throwable th) { 137 return false; 138 } 139 return true; 140 } 141 142 /** 143 * Checks whether the things are "quiet". All is currently does is check that 144 * something comes through the queue quickly enough as defined by 145 * <code>QUEUE_THROUGH_TIME</code> timeout. 146 * @return 147 */ 148 @Override 149 protected boolean isQuiet() { 150 emptyFunction.prepare(); 151 Platform.runLater(emptyFunction); 152 Environment.getEnvironment().getWaiter(MAX_ACTION_TIME).ensureState(new State<Object>() { 153 154 @Override 155 public Object reached() { 156 return emptyFunction.isExecuted() ? "" : null; 157 } 158 }); 159 return emptyFunction.getTime() <= QUEUE_THROUGH_TIME.getValue(); 160 } 161 162 class EmptyFunction implements Runnable { 163 164 private long time; 165 private long startTime; 166 private boolean executed; 167 168 @Override 169 public void run() { 170 time = System.currentTimeMillis() - startTime; 171 executed = true; 172 } 173 174 public boolean isExecuted() { 175 return executed; 176 } 177 178 public void prepare() { 179 executed = false; 180 startTime = System.currentTimeMillis(); 181 } 182 183 public long getTime() { 184 return time; 185 } 186 } 187 188 class WrapperFunction implements Runnable { 189 190 private Action action = null; 191 private Object[] parameters = null; 192 private boolean done = false; 193 194 public void setAction(Action action) { 195 this.action = action; 196 } 197 198 public void setParameters(Object[] parameters) { 199 this.parameters = parameters; 200 } 201 202 @Override 203 public void run() { 204 try { 205 action.execute(parameters); 206 } catch (RuntimeException e) { 207 } 208 synchronized (this) { 209 done = true; 210 notifyAll(); 211 } 212 } 213 214 public boolean isDone() { 215 return done; 216 } 217 218 public void clean() { 219 done = false; 220 action = null; 221 parameters = null; 222 } 223 224 public boolean failed() { 225 return !done || action.failed(); 226 } 227 228 public Throwable getThrowable() { 229 return action.getThrowable(); 230 } 231 232 public synchronized void waitDone(Timeout timeout) { 233 try { 234 long maxTime = System.currentTimeMillis() + timeout.getValue(); 235 while (!done && System.currentTimeMillis() < maxTime) { 236 wait(maxTime - System.currentTimeMillis()); 237 } 238 } catch (InterruptedException ex) { 239 } 240 } 241 } 242 }