jdk/test/sanity/client/lib/jemmy/src/org/netbeans/jemmy/Waiter.java
changeset 36744 a00905527ec2
equal deleted inserted replaced
36743:bdc3f1b79fb7 36744:a00905527ec2
       
     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  */
       
    23 package org.netbeans.jemmy;
       
    24 
       
    25 import java.awt.Component;
       
    26 
       
    27 /**
       
    28  *
       
    29  * Waits for something defined by Waitable interface to be happened.
       
    30  *
       
    31  * <BR><BR>Timeouts used: <BR>
       
    32  * Waiter.TimeDelta - time delta to check actionProduced result.<BR>
       
    33  * Waiter.WaitingTime - maximal waiting time<BR>
       
    34  * Waiter.AfterWaitingTime - time to sleep after waiting has been finished.<BR>
       
    35  *
       
    36  * @see Timeouts
       
    37  * @see Waitable
       
    38  *
       
    39  * @author Alexandre Iline (alexandre.iline@oracle.com)
       
    40  */
       
    41 public class Waiter<R, P> implements Waitable<R, P>, Timeoutable, Outputable {
       
    42 
       
    43     private final static long TIME_DELTA = 10;
       
    44     private final static long WAIT_TIME = 60000;
       
    45     private final static long AFTER_WAIT_TIME = 0;
       
    46 
       
    47     private final Waitable<R, P> waitable;
       
    48     private long startTime = 0;
       
    49     private long endTime = -1;
       
    50     private R result;
       
    51     private Timeouts timeouts;
       
    52     private String waitingTimeOrigin;
       
    53     private TestOut out;
       
    54 
       
    55     /**
       
    56      * Replace the fine-grained timeouts with a global flag which can be set,
       
    57      * for instance, by a separate thread when a global timeout runs out.
       
    58      */
       
    59     public static volatile boolean USE_GLOBAL_TIMEOUT = false;
       
    60     public static volatile boolean globalTimeoutExpired = false;
       
    61 
       
    62     /**
       
    63      * Constructor.
       
    64      *
       
    65      * @param w Waitable object defining waiting criteria.
       
    66      */
       
    67     public Waiter(Waitable<R, P> w) {
       
    68         super();
       
    69         if (w == null) {
       
    70             throw new NullPointerException("Waitable cannot be null");
       
    71         }
       
    72         setTimeouts(JemmyProperties.getProperties().getTimeouts());
       
    73         setOutput(JemmyProperties.getProperties().getOutput());
       
    74         waitable = w;
       
    75     }
       
    76 
       
    77     /**
       
    78      * Can be used from subclass. actionProduced() method must be overriden in
       
    79      * a class that uses this super constructor. actionProduced() method in
       
    80      * Waiter will throw UnsupportedOperationException whenever invoked.
       
    81      */
       
    82     protected Waiter() {
       
    83         super();
       
    84         setTimeouts(JemmyProperties.getProperties().getTimeouts());
       
    85         setOutput(JemmyProperties.getProperties().getOutput());
       
    86         waitable = null;
       
    87     }
       
    88 
       
    89     static {
       
    90         Timeouts.initDefault("Waiter.TimeDelta", TIME_DELTA);
       
    91         Timeouts.initDefault("Waiter.WaitingTime", WAIT_TIME);
       
    92         Timeouts.initDefault("Waiter.AfterWaitingTime", AFTER_WAIT_TIME);
       
    93     }
       
    94 
       
    95     /**
       
    96      * Defines current timeouts.
       
    97      *
       
    98      * @param timeouts A collection of timeout assignments.
       
    99      * @see org.netbeans.jemmy.Timeoutable
       
   100      * @see org.netbeans.jemmy.Timeouts
       
   101      * @see #getTimeouts
       
   102      */
       
   103     @Override
       
   104     public void setTimeouts(Timeouts timeouts) {
       
   105         this.timeouts = timeouts;
       
   106     }
       
   107 
       
   108     /**
       
   109      * Like {@link #setTimeouts(Timeouts)}, but clones the timeouts first, then
       
   110      * sets "Waiter.WaitingTime" to the timeout whose name is passed in. This
       
   111      * name is remembered for display in timeout error messages so people know
       
   112      * what to adjust.
       
   113      *
       
   114      * @param timeouts to be cloned and in which to look up "useAsWaitingTime".
       
   115      * @param useAsWaitingTime the name of the timeout to apply to
       
   116      * "Waiter.WaitingTime".
       
   117      * @param waitingTimeOrigin overrides {@code useAsWaitingTime} in timeout
       
   118      * reporting if non-null.
       
   119      * @return the cloned timeouts.
       
   120      */
       
   121     public Timeouts setTimeoutsToCloneOf(Timeouts timeouts,
       
   122             String useAsWaitingTime, String waitingTimeOrigin) {
       
   123         Timeouts t = timeouts.cloneThis();
       
   124         t.setTimeout("Waiter.WaitingTime", t.getTimeout(useAsWaitingTime));
       
   125         setTimeouts(t);
       
   126         setWaitingTimeOrigin((null != waitingTimeOrigin) ? waitingTimeOrigin : useAsWaitingTime);
       
   127         return t;
       
   128     }
       
   129 
       
   130     /**
       
   131      * @see #setTimeoutsToCloneOf(Timeouts, String, String)
       
   132      */
       
   133     public Timeouts setTimeoutsToCloneOf(Timeouts timeouts,
       
   134             String useAsWaitingTime) {
       
   135         return setTimeoutsToCloneOf(timeouts, useAsWaitingTime, null);
       
   136     }
       
   137 
       
   138     /**
       
   139      * Sets the origin of the current "Waiter.WaitingTime" to be shown in
       
   140      * timeout error messages
       
   141      *
       
   142      * @param origin is the name of the origin.
       
   143      */
       
   144     public void setWaitingTimeOrigin(String origin) {
       
   145         waitingTimeOrigin = origin;
       
   146     }
       
   147 
       
   148     /**
       
   149      * Return current timeouts.
       
   150      *
       
   151      * @return the collection of current timeout assignments.
       
   152      * @see org.netbeans.jemmy.Timeoutable
       
   153      * @see org.netbeans.jemmy.Timeouts
       
   154      * @see #setTimeouts
       
   155      */
       
   156     @Override
       
   157     public Timeouts getTimeouts() {
       
   158         return timeouts;
       
   159     }
       
   160 
       
   161     /**
       
   162      * Defines print output streams or writers.
       
   163      *
       
   164      * @param out Identify the streams or writers used for print output.
       
   165      * @see org.netbeans.jemmy.Outputable
       
   166      * @see org.netbeans.jemmy.TestOut
       
   167      * @see #getOutput
       
   168      */
       
   169     @Override
       
   170     public void setOutput(TestOut out) {
       
   171         this.out = out;
       
   172     }
       
   173 
       
   174     /**
       
   175      * Returns print output streams or writers.
       
   176      *
       
   177      * @return an object that contains references to objects for printing to
       
   178      * output and err streams.
       
   179      * @see org.netbeans.jemmy.Outputable
       
   180      * @see org.netbeans.jemmy.TestOut
       
   181      * @see #setOutput
       
   182      */
       
   183     @Override
       
   184     public TestOut getOutput() {
       
   185         return out;
       
   186     }
       
   187 
       
   188     /**
       
   189      * Waits for not null result of actionProduced method of Waitable
       
   190      * implementation passed into constructor.
       
   191      *
       
   192      * @param waitableObject Object to be passed into actionProduced method.
       
   193      * @return non null result of action.
       
   194      * @throws TimeoutExpiredException
       
   195      * @exception InterruptedException
       
   196      */
       
   197     public R waitAction(P waitableObject)
       
   198             throws InterruptedException {
       
   199         startTime = System.currentTimeMillis();
       
   200         out.printTrace(getWaitingStartedMessage());
       
   201         out.printGolden(getGoldenWaitingStartedMessage());
       
   202         long timeDelta = timeouts.getTimeout("Waiter.TimeDelta");
       
   203         while ((result = actionProduced(waitableObject)) == null) {
       
   204             Thread.sleep(timeDelta);
       
   205             if (timeoutExpired()) {
       
   206                 out.printError(getTimeoutExpiredMessage(timeFromStart()));
       
   207                 out.printGolden(getGoldenTimeoutExpiredMessage());
       
   208                 throw (new TimeoutExpiredException(getActualDescription()));
       
   209             }
       
   210         }
       
   211         endTime = System.currentTimeMillis();
       
   212         out.printTrace(getActionProducedMessage(endTime - startTime, result));
       
   213         out.printGolden(getGoldenActionProducedMessage());
       
   214         Thread.sleep(timeouts.getTimeout("Waiter.AfterWaitingTime"));
       
   215         return result;
       
   216     }
       
   217 
       
   218     /**
       
   219      * This method delegates call to the waitable passed in constructor. If a
       
   220      * subclass was created using protected no-parameters constructor, it should
       
   221      * implement its own actionProduced method() as this one will throw an
       
   222      * UnsupportedOperationException.
       
   223      * @see Waitable
       
   224      * @param obj
       
   225      */
       
   226     @Override
       
   227     public R actionProduced(P obj) {
       
   228         if (waitable != null) {
       
   229             return waitable.actionProduced(obj);
       
   230         } else {
       
   231             throw new UnsupportedOperationException("actionProduced() return "
       
   232                     + "value is not defined. It used to return Boolean.TRUE "
       
   233                     + "in previous versions of Jemmy.");
       
   234         }
       
   235     }
       
   236 
       
   237     /**
       
   238      * @see Waitable
       
   239      */
       
   240     @Override
       
   241     public String getDescription() {
       
   242         return "Unknown waiting";
       
   243     }
       
   244 
       
   245     @Override
       
   246     public String toString() {
       
   247         return "Waiter{" + "description = " + getDescription() + ", waitable=" + waitable + ", startTime=" + startTime + ", endTime=" + endTime + ", result=" + result + ", waitingTimeOrigin=" + waitingTimeOrigin + '}';
       
   248     }
       
   249 
       
   250     /**
       
   251      * Returns message to be printed before waiting start.
       
   252      *
       
   253      * @return a message.
       
   254      */
       
   255     protected String getWaitingStartedMessage() {
       
   256         return "Start to wait action \"" + getActualDescription() + "\"";
       
   257     }
       
   258 
       
   259     /**
       
   260      * Returns message to be printed when waiting timeout has been expired.
       
   261      *
       
   262      * @param timeSpent time from waiting start (milliseconds)
       
   263      * @return a message.
       
   264      */
       
   265     protected String getTimeoutExpiredMessage(long timeSpent) {
       
   266         return ("\"" + getActualDescription() + "\" action has not been produced in "
       
   267                 + timeSpent + " milliseconds");
       
   268     }
       
   269 
       
   270     /**
       
   271      * Returns message to be printed when waiting has been successfully
       
   272      * finished.
       
   273      *
       
   274      * @param timeSpent time from waiting start (milliseconds)
       
   275      * @param result result of Waitable.actionproduced method.
       
   276      * @return a message.
       
   277      */
       
   278     protected String getActionProducedMessage(long timeSpent, final Object result) {
       
   279         String resultToString;
       
   280         if (result instanceof Component) {
       
   281             // run toString in dispatch thread
       
   282             resultToString = new QueueTool().invokeSmoothly(
       
   283                     new QueueTool.QueueAction<String>("result.toString()") {
       
   284                 @Override
       
   285                 public String launch() {
       
   286                     return result.toString();
       
   287                 }
       
   288             }
       
   289             );
       
   290         } else {
       
   291             resultToString = result.toString();
       
   292         }
       
   293         return ("\"" + getActualDescription() + "\" action has been produced in "
       
   294                 + timeSpent + " milliseconds with result "
       
   295                 + "\n    : " + resultToString);
       
   296     }
       
   297 
       
   298     /**
       
   299      * Returns message to be printed int golden output before waiting start.
       
   300      *
       
   301      * @return a message.
       
   302      */
       
   303     protected String getGoldenWaitingStartedMessage() {
       
   304         return "Start to wait action \"" + getActualDescription() + "\"";
       
   305     }
       
   306 
       
   307     /**
       
   308      * Returns message to be printed int golden output when waiting timeout has
       
   309      * been expired.
       
   310      *
       
   311      * @return a message.
       
   312      */
       
   313     protected String getGoldenTimeoutExpiredMessage() {
       
   314         return "\"" + getActualDescription() + "\" action has not been produced";
       
   315     }
       
   316 
       
   317     /**
       
   318      * Returns message to be printed int golden output when waiting has been
       
   319      * successfully finished.
       
   320      *
       
   321      * @return a message.
       
   322      */
       
   323     protected String getGoldenActionProducedMessage() {
       
   324         return "\"" + getActualDescription() + "\" action has been produced";
       
   325     }
       
   326 
       
   327     /**
       
   328      * Returns time from waiting start.
       
   329      *
       
   330      * @return Time spent for waiting already.
       
   331      */
       
   332     protected long timeFromStart() {
       
   333         return System.currentTimeMillis() - startTime;
       
   334     }
       
   335 
       
   336     private String getActualDescription() {
       
   337         final String suffix = (null == waitingTimeOrigin) ? "" : " (" + waitingTimeOrigin + ")";
       
   338         if (waitable != null) {
       
   339             return waitable.getDescription() + suffix;
       
   340         } else {
       
   341             return getDescription() + suffix;
       
   342         }
       
   343     }
       
   344 
       
   345     private boolean timeoutExpired() {
       
   346         if (USE_GLOBAL_TIMEOUT) {
       
   347             return globalTimeoutExpired;
       
   348         }
       
   349         return timeFromStart() > timeouts.getTimeout("Waiter.WaitingTime");
       
   350     }
       
   351 
       
   352 }