/* * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.netbeans.jemmy; import java.util.Optional; /** * * Runs actions with or without waiting. * * <BR><BR>Timeouts used: <BR> * ActionProducer.MaxActionTime - time action should be finished in. <BR> * * @see Action * @see Timeouts * * @author Alexandre Iline (alexandre.iline@oracle.com) */ public class ActionProducer<R, P> extends Thread implements Action<R, P>, Waitable<Optional<R>, P>, Timeoutable { private final static long ACTION_TIMEOUT = 10000; private Action<R, P> action; private boolean needWait = true; private P parameter; private boolean finished; private R result = null; private Timeouts timeouts; private Waiter<Optional<R>, P> waiter; private TestOut output; private Throwable exception; /** * Creates a producer for an action. * * @param a Action implementation. */ public ActionProducer(Action<R, P> a) { super(); waiter = new Waiter<>(this); action = a; setTimeouts(JemmyProperties.getProperties().getTimeouts()); setOutput(JemmyProperties.getProperties().getOutput()); finished = false; exception = null; } /** * Creates a producer for an action. * * @param a Action implementation. * @param nw Defines if {@code produceAction} method should wait for * the end of action. */ public ActionProducer(Action<R, P> a, boolean nw) { super(); waiter = new Waiter<>(this); action = a; needWait = nw; setTimeouts(JemmyProperties.getProperties().getTimeouts()); setOutput(JemmyProperties.getProperties().getOutput()); finished = false; exception = null; } /** * Creates a producer. {@code produceAction} must be overridden. */ protected ActionProducer() { super(); waiter = new Waiter<>(this); setTimeouts(JemmyProperties.getProperties().getTimeouts()); setOutput(JemmyProperties.getProperties().getOutput()); finished = false; exception = null; } /** * Creates a producer. {@code produceAction} must be overridden. * * @param nw Defines if {@code produceAction} method should wait for * the end of action. */ protected ActionProducer(boolean nw) { super(); waiter = new Waiter<>(this); needWait = nw; setTimeouts(JemmyProperties.getProperties().getTimeouts()); setOutput(JemmyProperties.getProperties().getOutput()); finished = false; exception = null; } static { Timeouts.initDefault("ActionProducer.MaxActionTime", ACTION_TIMEOUT); } /** * Set all the time outs used by sleeps or waits used by the launched * action. * * @param ts An object containing timeout information. * @see org.netbeans.jemmy.Timeouts * @see org.netbeans.jemmy.Timeoutable * @see #getTimeouts */ @Override public void setTimeouts(Timeouts ts) { timeouts = ts; } /** * Get all the time outs used by sleeps or waits used by the launched * action. * * @return an object containing information about timeouts. * @see org.netbeans.jemmy.Timeouts * @see org.netbeans.jemmy.Timeoutable * @see #setTimeouts */ @Override public Timeouts getTimeouts() { return timeouts; } /** * Identity of the streams or writers used for print output. * * @param out An object containing print output assignments for output and * error streams. * @see org.netbeans.jemmy.TestOut * @see org.netbeans.jemmy.Outputable */ public void setOutput(TestOut out) { output = out; waiter.setOutput(output); } /** * Returns the exception value. * * @return a Throwable object representing the exception value */ public Throwable getException() { return exception; } /** * Defines action priority in terms of thread priority. Increase (decrease) * parameter value to Thread.MIN_PRIORITY(MAX_PRIORITY) in case if it is * less(more) then it. * * @param newPriority New thread priority. */ public void setActionPriority(int newPriority) { int priority; if (newPriority < Thread.MIN_PRIORITY) { priority = MIN_PRIORITY; } else if (newPriority > Thread.MAX_PRIORITY) { priority = MAX_PRIORITY; } else { priority = newPriority; } try { setPriority(priority); } catch (IllegalArgumentException | SecurityException e) { e.printStackTrace(); } } /** * Get the result of a launched action. * * @return a launched action's result. without waiting in case if * {@code getFinished()} * @see #getFinished() */ public R getResult() { return result; } /** * Check if a launched action has finished. * * @return {@code true} if the launched action has completed, either * normally or with an exception; {@code false} otherwise. */ public boolean getFinished() { synchronized (this) { return finished; } } /** * Does nothing; the method should be overridden by inheritors. * * @param obj An object used to modify execution. This might be a * {@code java.lang.String[]} that lists a test's command line * arguments. * @return An object - result of the action. * @see org.netbeans.jemmy.Action */ @Override public R launch(P obj) { return null; } /** * @return this {@code ActionProducer}'s description. * @see Action */ @Override public String getDescription() { if (action != null) { return action.getDescription(); } else { return "Unknown action"; } } /** * Starts execution. Uses ActionProducer.MaxActionTime timeout. * * @param obj Parameter to be passed into action's * {@code launch(Object)} method. This parameter might be a * {@code java.lang.String[]} that lists a test's command line * arguments. * @param actionTimeOrigin is used for timeout reporting, if non-null. * @return {@code launch(Object)} result. * @throws TimeoutExpiredException * @exception InterruptedException */ public R produceAction(P obj, String actionTimeOrigin) throws InterruptedException { parameter = obj; synchronized (this) { finished = false; } start(); if (needWait) { waiter.setTimeoutsToCloneOf(timeouts, "ActionProducer.MaxActionTime", actionTimeOrigin); try { waiter.waitAction(null); } catch (TimeoutExpiredException e) { output.printError("Timeout for \"" + getDescription() + "\" action has been expired. Thread has been interrupted."); interrupt(); throw (e); } } return result; } /** * Launch an action in a separate thread of execution. When the action * finishes, record that fact. If the action finishes normally, store it's * result. Use {@code getFinished()} and {@code getResult} to * answer questions about test completion and return value, respectively. * * @see #getFinished() * @see #getResult() * @see java.lang.Runnable */ @Override public final void run() { result = null; try { result = launchAction(parameter); } catch (Throwable e) { exception = e; } synchronized (this) { finished = true; } } /** * Inquire for a reference to the object returned by a launched action. * * @param obj Not used. * @return the result returned when a launched action finishes normally. * @see org.netbeans.jemmy.Waitable */ @Override public final Optional<R> actionProduced(P obj) { synchronized (this) { if (finished) { return Optional.ofNullable(result); } else { return null; } } } /** * Launch some action. Pass the action parameters and get it's return value, * too. * * @param obj Parameter used to configure the execution of whatever this * {@code ActionProducer} puts into execution. * @return the return value of the action. */ private R launchAction(P obj) { if (action != null) { return action.launch(obj); } else { return launch(obj); } } @Override public String toString() { return "ActionProducer{" + "action=" + action + ", needWait=" + needWait + ", parameter=" + parameter + ", finished=" + finished + ", result=" + result + ", exception=" + exception + '}'; } }