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.
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 */
23package org.netbeans.jemmy;
24
25import java.io.FileInputStream;
26import java.io.FileNotFoundException;
27import java.io.IOException;
28import java.io.InputStream;
29import java.io.PrintStream;
30import java.io.PrintWriter;
31import java.util.Enumeration;
32import java.util.Hashtable;
33import java.util.Properties;
34
35/**
36 *
37 * Class to store and process a set of timeout values.
38 *
39 * @see #setDefault(String, long)
40 * @see #getDefault(String)
41 * @see #setTimeout(String, long)
42 * @see #getTimeout(String)
43 *
44 * @author Alexandre Iline (alexandre.iline@oracle.com)
45 */
46public class Timeouts {
47
48    private static final long DELTA_TIME = 100;
49
50    private static Timeouts defaults;
51
52    private Hashtable<String, Long> timeouts;
53    private static double timeoutsScale = -1;
54
55    /**
56     * Creates empty Timeouts object.
57     */
58    public Timeouts() {
59        super();
60        timeouts = new Hashtable<>();
61        setTimeout("Timeouts.DeltaTimeout", DELTA_TIME);
62        try {
63            load();
64        } catch (IOException ignored) {
65        }
66    }
67
68    /**
69     * Stores default timeout value.
70     *
71     * @param name Timeout name.
72     * @param newValue Timeout value.
73     * @see #getDefault(String)
74     * @see #initDefault(String, long)
75     * @see #containsDefault(String)
76     */
77    public static void setDefault(String name, long newValue) {
78        defaults.setTimeout(name, newValue);
79    }
80
81    /**
82     * Sets default timeout value if it was not set before.
83     *
84     * @param name Timeout name.
85     * @param newValue Timeout value.
86     * @see #setDefault(String, long)
87     * @see #getDefault(String)
88     * @see #containsDefault(String)
89     */
90    public static void initDefault(String name, long newValue) {
91        defaults.initTimeout(name, newValue);
92    }
93
94    /**
95     * Gets default timeout value.
96     *
97     * @param name Timeout name.
98     * @return Timeout value or -1 if timeout is not defined.
99     * @see #setDefault(String, long)
100     * @see #initDefault(String, long)
101     * @see #containsDefault(String)
102     */
103    public static long getDefault(String name) {
104        return defaults.getTimeout(name);
105    }
106
107    /**
108     * Check that default timeout value was defined.
109     *
110     * @param name Timeout name.
111     * @return True if timeout has been defined, false otherwise.
112     * @see #setDefault(String, long)
113     * @see #getDefault(String)
114     * @see #initDefault(String, long)
115     */
116    public static boolean containsDefault(String name) {
117        return defaults.contains(name);
118    }
119
120    static {
121        defaults = new Timeouts();
122    }
123
124    /**
125     * Loads default timeouts values.
126     *
127     * @param stream Stream to load timeouts from.
128     * @see org.netbeans.jemmy.Timeouts#loadDefaults(String)
129     * @see org.netbeans.jemmy.Timeouts#loadDefaults()
130     * @exception IOException
131     */
132    public void loadDefaults(InputStream stream)
133            throws IOException {
134        defaults.load(stream);
135    }
136
137    /**
138     * Loads default timeouts values from file.
139     *
140     * @param fileName File to load timeouts from.
141     * @see org.netbeans.jemmy.Timeouts#loadDefaults(InputStream)
142     * @see org.netbeans.jemmy.Timeouts#loadDefaults(String)
143     * @exception IOException
144     * @exception FileNotFoundException
145     */
146    public void loadDefaults(String fileName)
147            throws FileNotFoundException, IOException {
148        defaults.load(fileName);
149    }
150
151    /**
152     * Loads default timeouts values. Uses jemmy.timeouts system property to get
153     * timeouts file.
154     *
155     * @see org.netbeans.jemmy.Timeouts#loadDefaults(InputStream)
156     * @see org.netbeans.jemmy.Timeouts#loadDefaults(String)
157     * @exception IOException
158     * @exception FileNotFoundException
159     */
160    public void loadDefaults()
161            throws FileNotFoundException, IOException {
162        defaults.load();
163    }
164
165    /**
166     * Creates Timeout new object by name and getTimeout(name) value.
167     *
168     * @param name Timeout name.
169     * @return a Timeout instance.
170     */
171    public Timeout create(String name) {
172        return new Timeout(name, getTimeout(name));
173    }
174
175    /**
176     * Create timeout for "Timeouts.DeltaTimeout" name.
177     *
178     * @return a Timeout instance.
179     */
180    public Timeout createDelta() {
181        return create("Timeouts.DeltaTimeout");
182    }
183
184    /**
185     * Checks if timeout has already been defined in this timeout instance.
186     *
187     * @param name Timeout name.
188     * @return True if timeout has been defined, false otherwise.
189     * @see #containsDefault(String)
190     */
191    public boolean contains(String name) {
192        return timeouts.containsKey(name);
193    }
194
195    /**
196     * Sets new timeout value.
197     *
198     * @param name Timeout name.
199     * @param newValue Timeout value.
200     * @return old timeout value
201     * @see #getTimeout
202     */
203    public long setTimeout(String name, long newValue) {
204        long oldValue = -1;
205        if (contains(name)) {
206            oldValue = getTimeout(name);
207            timeouts.remove(name);
208        }
209        timeouts.put(name, newValue);
210        return oldValue;
211    }
212
213    /**
214     * Gets timeout value. It timeout was not defined in this instance, returns
215     * default timeout value.
216     *
217     * @param name Timeout name.
218     * @return Timeout value.
219     * @see #getDefault(String)
220     * @see #setTimeout
221     */
222    public long getTimeout(String name) {
223        long timeout;
224        if (contains(name) && timeouts.get(name) != null) {
225            timeout = timeouts.get(name);
226            timeout = (long) ((double) timeout * getTimeoutsScale());
227        } else if (this != defaults) {
228            timeout = getDefault(name);
229        } else {
230            timeout = -1;
231        }
232        return timeout;
233    }
234
235    /**
236     * Gets "Timeouts.DeltaTimeout" timeout value.
237     *
238     * @return Timeout value.
239     * @see #getDefault(String)
240     */
241    public long getDeltaTimeout() {
242        return getTimeout("Timeouts.DeltaTimeout");
243    }
244
245    /**
246     * Sets timeout value if it was not set before.
247     *
248     * @param name Timeout name.
249     * @param newValue Timeout value.
250     * @return old timeout value
251     */
252    public long initTimeout(String name, long newValue) {
253        long result = getTimeout(name);
254        if (!contains(name)) {
255            setTimeout(name, newValue);
256        }
257        return result;
258    }
259
260    /**
261     * Creates a copy of the current timeouts set.
262     *
263     * @return A copy.
264     */
265    public Timeouts cloneThis() {
266        Timeouts t = new Timeouts();
267        Enumeration<String> e = timeouts.keys();
268        String name = "";
269        while (e.hasMoreElements()) {
270            name = e.nextElement();
271            t.setTimeout(name,
272                    getTimeout(name));
273        }
274        return t;
275    }
276
277    /**
278     * Sleeps for the "name" timeout value. Can throw InterruptedException if
279     * current thread was interrupted.
280     *
281     * @param name Timeout name.
282     * @exception InterruptedException
283     */
284    public void eSleep(String name) throws InterruptedException {
285        if (contains(name)
286                || defaults.contains(name)) {
287            Thread.sleep(getTimeout(name));
288        }
289    }
290
291    /**
292     * Sleeps for the "name" timeout value. Does not throw InterruptedException
293     * anyway.
294     *
295     * @param name Timeout name.
296     */
297    public void sleep(String name) {
298        create(name).sleep();
299    }
300
301    /**
302     * Prints all defined timeouts.
303     *
304     * @param pw PrintWriter to print into.
305     */
306    public void print(PrintWriter pw) {
307        Enumeration<String> e = timeouts.keys();
308        String name = "";
309        while (e.hasMoreElements()) {
310            name = e.nextElement();
311            pw.println(name + " = " + Long.toString(getTimeout(name)));
312        }
313        pw.println("Default values:");
314        e = defaults.timeouts.keys();
315        name = "";
316        while (e.hasMoreElements()) {
317            name = e.nextElement();
318            if (!contains(name)) {
319                pw.println(name + " = " + Long.toString(getDefault(name)));
320            }
321        }
322    }
323
324    /**
325     * Prins all defined timeouts.
326     *
327     * @param ps PrintStream to print into.
328     */
329    public void print(PrintStream ps) {
330        print(new PrintWriter(ps));
331    }
332
333    /**
334     * Loads timeouts values.
335     *
336     * @param stream Stream to load timeouts from.
337     * @see org.netbeans.jemmy.Timeouts#load(String)
338     * @see org.netbeans.jemmy.Timeouts#load()
339     * @exception IOException
340     */
341    public void load(InputStream stream)
342            throws IOException {
343        Properties props = new Properties();
344        props.load(stream);
345        Enumeration<?> propNames = props.propertyNames();
346        long propValue;
347        String propName = null;
348        while (propNames.hasMoreElements()) {
349            propName = (String) propNames.nextElement();
350            propValue = Long.parseLong(props.getProperty(propName));
351            setTimeout(propName, propValue);
352        }
353    }
354
355    /**
356     * Loads timeouts values from file.
357     *
358     * @param fileName File to load timeouts from.
359     * @see org.netbeans.jemmy.Timeouts#load(InputStream)
360     * @see org.netbeans.jemmy.Timeouts#load(String)
361     * @exception IOException
362     * @exception FileNotFoundException
363     */
364    public void load(String fileName)
365            throws FileNotFoundException, IOException {
366        try (FileInputStream fileInputStream = new FileInputStream(fileName)) {
367            load(fileInputStream);
368        }
369    }
370
371    /**
372     * Loads timeouts values. Uses jemmy.timeouts system property to get
373     * timeouts file.
374     *
375     * @see org.netbeans.jemmy.Timeouts#load(InputStream)
376     * @see org.netbeans.jemmy.Timeouts#load(String)
377     * @exception IOException
378     * @exception FileNotFoundException
379     */
380    public void load()
381            throws FileNotFoundException, IOException {
382        if (System.getProperty("jemmy.timeouts") != null
383                && !System.getProperty("jemmy.timeouts").equals("")) {
384            load(System.getProperty("jemmy.timeouts"));
385        }
386    }
387
388    /**
389     * Loads debug timeouts values.
390     *
391     * @exception IOException
392     */
393    public void loadDebugTimeouts() throws IOException {
394        load(getClass().getClassLoader().getResourceAsStream("org/netbeans/jemmy/debug.timeouts"));
395    }
396
397    /**
398     * Get timeouts scale. Uses jemmy.timeouts.scale system property to get the
399     * value.
400     *
401     * @return timeouts scale or 1 if the property is not set.
402     */
403    public static double getTimeoutsScale() {
404        if (timeoutsScale == -1) {
405            String s = System.getProperty("jemmy.timeouts.scale", "1");
406            try {
407                timeoutsScale = Double.parseDouble(s);
408            } catch (NumberFormatException e) {
409                timeoutsScale = 1;
410            }
411        }
412        if (timeoutsScale < 0) {
413            timeoutsScale = 1;
414        }
415        return timeoutsScale;
416    }
417
418    /**
419     * This method is designed to be used by unit test for testing purpose.
420     */
421    static void resetTimeoutScale() {
422        timeoutsScale = -1;
423    }
424}
425