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