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. 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.netbeans.jemmy; 26 27 import java.util.Optional; 28 29 /** 30 * 31 * Runs actions with or without waiting. 32 * 33 * <BR><BR>Timeouts used: <BR> 34 * ActionProducer.MaxActionTime - time action should be finished in. <BR> 35 * 36 * @see Action 37 * @see Timeouts 38 * 39 * @author Alexandre Iline (alexandre.iline@oracle.com) 40 */ 41 public class ActionProducer<R, P> extends Thread 42 implements Action<R, P>, Waitable<Optional<R>, P>, Timeoutable { 43 44 private final static long ACTION_TIMEOUT = 10000; 45 46 private Action<R, P> action; 47 private boolean needWait = true; 48 private P parameter; 49 private boolean finished; 50 private R result = null; 51 private Timeouts timeouts; 52 private Waiter<Optional<R>, P> waiter; 53 private TestOut output; 54 private Throwable exception; 55 56 /** 57 * Creates a producer for an action. 58 * 59 * @param a Action implementation. 60 */ ActionProducer(Action<R, P> a)61 public ActionProducer(Action<R, P> a) { 62 super(); 63 waiter = new Waiter<>(this); 64 action = a; 65 setTimeouts(JemmyProperties.getProperties().getTimeouts()); 66 setOutput(JemmyProperties.getProperties().getOutput()); 67 finished = false; 68 exception = null; 69 } 70 71 /** 72 * Creates a producer for an action. 73 * 74 * @param a Action implementation. 75 * @param nw Defines if {@code produceAction} method should wait for 76 * the end of action. 77 */ ActionProducer(Action<R, P> a, boolean nw)78 public ActionProducer(Action<R, P> a, boolean nw) { 79 super(); 80 waiter = new Waiter<>(this); 81 action = a; 82 needWait = nw; 83 setTimeouts(JemmyProperties.getProperties().getTimeouts()); 84 setOutput(JemmyProperties.getProperties().getOutput()); 85 finished = false; 86 exception = null; 87 } 88 89 /** 90 * Creates a producer. {@code produceAction} must be overridden. 91 */ ActionProducer()92 protected ActionProducer() { 93 super(); 94 waiter = new Waiter<>(this); 95 setTimeouts(JemmyProperties.getProperties().getTimeouts()); 96 setOutput(JemmyProperties.getProperties().getOutput()); 97 finished = false; 98 exception = null; 99 } 100 101 /** 102 * Creates a producer. {@code produceAction} must be overridden. 103 * 104 * @param nw Defines if {@code produceAction} method should wait for 105 * the end of action. 106 */ ActionProducer(boolean nw)107 protected ActionProducer(boolean nw) { 108 super(); 109 waiter = new Waiter<>(this); 110 needWait = nw; 111 setTimeouts(JemmyProperties.getProperties().getTimeouts()); 112 setOutput(JemmyProperties.getProperties().getOutput()); 113 finished = false; 114 exception = null; 115 } 116 117 static { 118 Timeouts.initDefault("ActionProducer.MaxActionTime", ACTION_TIMEOUT); 119 } 120 121 /** 122 * Set all the time outs used by sleeps or waits used by the launched 123 * action. 124 * 125 * @param ts An object containing timeout information. 126 * @see org.netbeans.jemmy.Timeouts 127 * @see org.netbeans.jemmy.Timeoutable 128 * @see #getTimeouts 129 */ 130 @Override setTimeouts(Timeouts ts)131 public void setTimeouts(Timeouts ts) { 132 timeouts = ts; 133 } 134 135 /** 136 * Get all the time outs used by sleeps or waits used by the launched 137 * action. 138 * 139 * @return an object containing information about timeouts. 140 * @see org.netbeans.jemmy.Timeouts 141 * @see org.netbeans.jemmy.Timeoutable 142 * @see #setTimeouts 143 */ 144 @Override getTimeouts()145 public Timeouts getTimeouts() { 146 return timeouts; 147 } 148 149 /** 150 * Identity of the streams or writers used for print output. 151 * 152 * @param out An object containing print output assignments for output and 153 * error streams. 154 * @see org.netbeans.jemmy.TestOut 155 * @see org.netbeans.jemmy.Outputable 156 */ setOutput(TestOut out)157 public void setOutput(TestOut out) { 158 output = out; 159 waiter.setOutput(output); 160 } 161 162 /** 163 * Returns the exception value. 164 * 165 * @return a Throwable object representing the exception value 166 */ getException()167 public Throwable getException() { 168 return exception; 169 } 170 171 /** 172 * Defines action priority in terms of thread priority. Increase (decrease) 173 * parameter value to Thread.MIN_PRIORITY(MAX_PRIORITY) in case if it is 174 * less(more) then it. 175 * 176 * @param newPriority New thread priority. 177 */ setActionPriority(int newPriority)178 public void setActionPriority(int newPriority) { 179 int priority; 180 if (newPriority < Thread.MIN_PRIORITY) { 181 priority = MIN_PRIORITY; 182 } else if (newPriority > Thread.MAX_PRIORITY) { 183 priority = MAX_PRIORITY; 184 } else { 185 priority = newPriority; 186 } 187 try { 188 setPriority(priority); 189 } catch (IllegalArgumentException | SecurityException e) { 190 e.printStackTrace(); 191 } 192 } 193 194 /** 195 * Get the result of a launched action. 196 * 197 * @return a launched action's result. without waiting in case if 198 * {@code getFinished()} 199 * @see #getFinished() 200 */ getResult()201 public R getResult() { 202 return result; 203 } 204 205 /** 206 * Check if a launched action has finished. 207 * 208 * @return {@code true} if the launched action has completed, either 209 * normally or with an exception; {@code false} otherwise. 210 */ getFinished()211 public boolean getFinished() { 212 synchronized (this) { 213 return finished; 214 } 215 } 216 217 /** 218 * Does nothing; the method should be overridden by inheritors. 219 * 220 * @param obj An object used to modify execution. This might be a 221 * {@code java.lang.String[]} that lists a test's command line 222 * arguments. 223 * @return An object - result of the action. 224 * @see org.netbeans.jemmy.Action 225 */ 226 @Override launch(P obj)227 public R launch(P obj) { 228 return null; 229 } 230 231 /** 232 * @return this {@code ActionProducer}'s description. 233 * @see Action 234 */ 235 @Override getDescription()236 public String getDescription() { 237 if (action != null) { 238 return action.getDescription(); 239 } else { 240 return "Unknown action"; 241 } 242 } 243 244 /** 245 * Starts execution. Uses ActionProducer.MaxActionTime timeout. 246 * 247 * @param obj Parameter to be passed into action's 248 * {@code launch(Object)} method. This parameter might be a 249 * {@code java.lang.String[]} that lists a test's command line 250 * arguments. 251 * @param actionTimeOrigin is used for timeout reporting, if non-null. 252 * @return {@code launch(Object)} result. 253 * @throws TimeoutExpiredException 254 * @exception InterruptedException 255 */ produceAction(P obj, String actionTimeOrigin)256 public R produceAction(P obj, String actionTimeOrigin) throws InterruptedException { 257 parameter = obj; 258 synchronized (this) { 259 finished = false; 260 } 261 start(); 262 if (needWait) { 263 waiter.setTimeoutsToCloneOf(timeouts, "ActionProducer.MaxActionTime", actionTimeOrigin); 264 try { 265 waiter.waitAction(null); 266 } catch (TimeoutExpiredException e) { 267 output.printError("Timeout for \"" + getDescription() 268 + "\" action has been expired. Thread has been interrupted."); 269 interrupt(); 270 throw (e); 271 } 272 } 273 return result; 274 } 275 276 /** 277 * Launch an action in a separate thread of execution. When the action 278 * finishes, record that fact. If the action finishes normally, store it's 279 * result. Use {@code getFinished()} and {@code getResult} to 280 * answer questions about test completion and return value, respectively. 281 * 282 * @see #getFinished() 283 * @see #getResult() 284 * @see java.lang.Runnable 285 */ 286 @Override run()287 public final void run() { 288 result = null; 289 try { 290 result = launchAction(parameter); 291 } catch (Throwable e) { 292 exception = e; 293 } 294 synchronized (this) { 295 finished = true; 296 } 297 } 298 299 /** 300 * Inquire for a reference to the object returned by a launched action. 301 * 302 * @param obj Not used. 303 * @return the result returned when a launched action finishes normally. 304 * @see org.netbeans.jemmy.Waitable 305 */ 306 @Override actionProduced(P obj)307 public final Optional<R> actionProduced(P obj) { 308 synchronized (this) { 309 if (finished) { 310 return Optional.ofNullable(result); 311 } else { 312 return null; 313 } 314 } 315 } 316 317 /** 318 * Launch some action. Pass the action parameters and get it's return value, 319 * too. 320 * 321 * @param obj Parameter used to configure the execution of whatever this 322 * {@code ActionProducer} puts into execution. 323 * @return the return value of the action. 324 */ launchAction(P obj)325 private R launchAction(P obj) { 326 if (action != null) { 327 return action.launch(obj); 328 } else { 329 return launch(obj); 330 } 331 } 332 333 @Override toString()334 public String toString() { 335 return "ActionProducer{" + "action=" + action + ", needWait=" + needWait + ", parameter=" + parameter + ", finished=" + finished + ", result=" + result + ", exception=" + exception + '}'; 336 } 337 } 338