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