1 /*
   2  * Copyright (c) 2007, 2017 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.jemmy.action;
  26 
  27 
  28 import java.util.LinkedList;
  29 import org.jemmy.JemmyException;
  30 import org.jemmy.TimeoutExpiredException;
  31 
  32 
  33 /**
  34  *
  35  * @author shura, KAM
  36  */
  37 class ActionQueue {
  38 
  39     private Thread queueThread;
  40     private final LinkedList<ActionRecord> queue;
  41     private boolean stop = false;
  42 
  43     public ActionQueue() {
  44         queue = new LinkedList<ActionRecord>();
  45         queueThread = new Thread(new Runnable() {
  46 
  47             public void run() {
  48                 int size;
  49                 while (!stop) {
  50                     synchronized (queue) {
  51                         size = queue.size();
  52                         if (size == 0) {
  53                             try {
  54                                 queue.wait();
  55                             } catch (InterruptedException ex) {
  56                             }
  57                         }
  58                     }
  59                     if (size > 0) {
  60                         ActionRecord r;
  61                         synchronized (queue) {
  62                             r = queue.poll();
  63                         }
  64                         try {
  65                             r.execute();
  66                         } catch (Exception e) {
  67                             System.err.println("Action '" + r + "' failed with the following exception: ");
  68                             e.printStackTrace(System.err);
  69                             System.err.flush();
  70                         }
  71                         r.setCompleted(true);
  72                     }
  73                 }
  74             }
  75         }, "ActionQueue.queueThread");
  76         queueThread.start();
  77     }
  78 
  79     public int actionsInQueue() {
  80         synchronized(queue) {
  81             return queue.size();
  82         }
  83     }
  84 
  85     public void stop() {
  86         stop = true;
  87     }
  88 
  89     /**
  90      * Returns internal ActionQueue event dispatching thread
  91      * @return queue dispatching thread of ActionQueue object
  92      */
  93     public Thread getQueueThread() {
  94         return queueThread;
  95     }
  96 
  97     /**
  98      * Schedules execution of an action throught the internal ActionQueue queue
  99      * and exits immediately
 100      * @param action action to execute
 101      * @param parameters parameters to pass to action.run() method
 102      */
 103     public void invoke(Action action, Object... parameters) {
 104         synchronized (queue) {
 105             queue.add(new ActionRecord(action, parameters));
 106             queue.notifyAll();
 107         }
 108     }
 109 
 110     /**
 111      * Schedules execution of an action through the internal ActionQueue queue
 112      * and waits until it is completed
 113      * @param action action to execute
 114      * @param parameters parameters to pass to action.run() method
 115      */
 116     public void invokeAndWait(Action action, Object... parameters) {
 117         ActionRecord r = new ActionRecord(action, parameters);
 118         synchronized (queue) {
 119             queue.add(r);
 120             queue.notifyAll();
 121         }
 122         r.waitCompleted();
 123 
 124         if (r.failed()) {
 125             throw new JemmyException("Action '" + r + "' invoked through ActionQueue failed", r.getThrowable());
 126         }
 127     }
 128 
 129     private class ActionRecord {
 130 
 131         Action action;
 132         Object[] parameters;
 133         boolean completed;
 134         boolean started;
 135 
 136         public ActionRecord(Action action, Object[] parameters) {
 137             this.action = action;
 138             this.parameters = parameters;
 139         }
 140 
 141         public boolean failed() {
 142             return action.failed();
 143         }
 144 
 145         public Throwable getThrowable() {
 146             return action.getThrowable();
 147         }
 148 
 149         public Object[] getParameters() {
 150             return parameters;
 151         }
 152 
 153         public boolean isCompleted() {
 154             return completed;
 155         }
 156 
 157         public synchronized void setCompleted(boolean completed) {
 158             this.completed = completed;
 159             notifyAll();
 160         }
 161 
 162         public void execute() {
 163             synchronized (this) {
 164                 started = true;
 165                 notifyAll();
 166             }
 167             action.execute(parameters);
 168         }
 169 
 170         public synchronized void waitCompleted() {
 171             try {
 172                 while (!started) {
 173                     wait();
 174                 }
 175                 if (!completed) {
 176                     wait(action.getAllowedTime());
 177                     if (!completed) {
 178                         action.interrupt();
 179                         throw new TimeoutExpiredException("Action did not finish in " + action.getAllowedTime() + " ms: " + action);
 180                     }
 181                 }
 182             } catch (InterruptedException ex) {
 183             }
 184         }
 185 
 186         @Override
 187         public String toString() {
 188             return action.toString();
 189         }
 190     }
 191 }