001/* A FIFO queue receiver with variable capacity and optional history. 002 003 Copyright (c) 1997-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 028 */ 029package ptolemy.actor; 030 031import java.util.Collections; 032import java.util.Enumeration; 033import java.util.List; 034import java.util.NoSuchElementException; 035 036import ptolemy.actor.util.FIFOQueue; 037import ptolemy.data.Token; 038import ptolemy.kernel.util.IllegalActionException; 039 040/////////////////////////////////////////////////////////////////// 041//// QueueReceiver 042 043/** 044 A first-in, first-out (FIFO) queue receiver with variable capacity and 045 optional history. Tokens are put into the receiver with the put() method, 046 and removed from the receiver with the get() method. The token removed is 047 the oldest one in the receiver. By default, the capacity is unbounded, but 048 it can be set to any nonnegative size. If the history capacity is greater 049 than zero (or infinite, indicated by a capacity of INFINITE_CAPACITY), 050 then tokens removed from the receiver are stored in a history queue rather 051 than simply removed. By default, the history capacity is zero. 052 053 @author Edward A. Lee, Lukito Muliadi, Xiaojun Liu 054 @version $Id$ 055 @since Ptolemy II 0.2 056 @Pt.ProposedRating Green (eal) 057 @Pt.AcceptedRating Green (liuj) 058 @see ptolemy.actor.util.FIFOQueue 059 */ 060public class QueueReceiver extends AbstractReceiver { 061 /** Construct an empty receiver with no container. 062 */ 063 public QueueReceiver() { 064 super(); 065 } 066 067 /** Construct an empty receiver with the specified container. 068 * @param container The container of the receiver. 069 * @exception IllegalActionException If the container does 070 * not accept this receiver. 071 */ 072 public QueueReceiver(IOPort container) throws IllegalActionException { 073 super(container); 074 } 075 076 /////////////////////////////////////////////////////////////////// 077 //// public methods //// 078 079 /** Clear this receiver of any contained tokens. 080 */ 081 @Override 082 public void clear() { 083 _queue.clear(); 084 } 085 086 /** List the tokens in the receiver, beginning with the oldest. 087 * @return An enumeration of tokens. 088 */ 089 @Override 090 public List<Token> elementList() { 091 return _queue.elementList(); 092 } 093 094 /** Enumerate the tokens in the receiver, beginning with the oldest. 095 * @deprecated Used elementList() instead. 096 * @return An enumeration of tokens. 097 */ 098 @Deprecated 099 public Enumeration elements() { 100 return Collections.enumeration(elementList()); 101 } 102 103 /** Remove the first token (the oldest one) from the receiver and 104 * return it. If there is no token in the receiver, throw an 105 * exception. 106 * @return The oldest token in the receiver. 107 * @exception NoTokenException If there is no token in the receiver. 108 */ 109 @Override 110 public Token get() { 111 Token t = null; 112 113 try { 114 t = (Token) _queue.take(); 115 } catch (NoSuchElementException ex) { 116 // The queue is empty. 117 throw new NoTokenException(getContainer(), 118 "Attempt to get token from an empty QueueReceiver."); 119 } 120 121 return t; 122 } 123 124 /** Return a token in the receiver or its history. If the offset 125 * argument is zero, return the oldest token in the receiver. 126 * If the offset is 1, return the second oldest token, etc. The 127 * token is not removed from the receiver. If there is no such 128 * token in the receiver (the offset is greater than or equal 129 * to the number of tokens currently in the receiver), throw an 130 * exception. If the offset is -1, return the most recent token 131 * removed from the receiver. If it is -2, return the second 132 * most recent token removed from the receiver, etc. If there is 133 * no such token in the receiver's history (the history capacity 134 * is zero or the absolute value of offset is greater than the 135 * number of tokens currently in the receiver's history), an 136 * exception is thrown. 137 * @param offset The offset from the oldest token in the receiver. 138 * @return The token at the desired offset in the receiver or its 139 * history. 140 * @exception NoTokenException If the offset is out of range. 141 */ 142 public Token get(int offset) { 143 try { 144 return (Token) _queue.get(offset); 145 } catch (NoSuchElementException ex) { 146 throw new NoTokenException(getContainer(), 147 "Offset " + offset + " out of range with " + _queue.size() 148 + " tokens in the receiver and " 149 + _queue.historySize() + " in history."); 150 } 151 } 152 153 /** Return the capacity, or INFINITE_CAPACITY if it is unbounded. 154 * @return The capacity of the receiver. 155 * @see #setCapacity(int) 156 */ 157 public int getCapacity() { 158 return _queue.getCapacity(); 159 } 160 161 /** Return the capacity of the history queue. 162 * This will be zero if the history mechanism is disabled 163 * and INFINITE_CAPACITY if the history capacity is unbounded. 164 * @return The capacity of the history queue. 165 * @see #setHistoryCapacity(int) 166 */ 167 public int getHistoryCapacity() { 168 return _queue.getHistoryCapacity(); 169 } 170 171 /** Return true if the next call to put() will succeed without 172 * a NoRoomException. 173 * @return True if the queue has room for one more token. 174 */ 175 @Override 176 public boolean hasRoom() { 177 return !_queue.isFull(); 178 } 179 180 /** Return true if the queue has room to put the given number of 181 * tokens into it (via the put() method). 182 * @param numberOfTokens The number of tokens to put into the queue. 183 * @return True if the queue has room for the specified number of tokens. 184 * @exception IllegalArgumentException If the number of tokens is less 185 * than one. This is a runtime exception, and hence does not need to 186 * be explicitly declared by the caller. 187 */ 188 @Override 189 public boolean hasRoom(int numberOfTokens) throws IllegalArgumentException { 190 if (numberOfTokens < 1) { 191 throw new IllegalArgumentException( 192 "The number of tokens must be greater than 0"); 193 } 194 195 return _queue.size() + numberOfTokens < _queue.getCapacity(); 196 } 197 198 /** Return true if the next call to get() will succeed without a 199 * a NoTokenException. 200 * @return True if the queue has at least one token in it. 201 */ 202 @Override 203 public boolean hasToken() { 204 return _queue.size() > 0; 205 } 206 207 /** Return true if the specified number of tokens is available in the 208 * queue. 209 * @param numberOfTokens The number of tokens to get from the queue. 210 * @return True if the specified number of tokens is available. 211 * @exception IllegalArgumentException If the number of tokens is less 212 * than one. This is a runtime exception, and hence does not need to 213 * be explicitly declared by the caller. 214 */ 215 @Override 216 public boolean hasToken(int numberOfTokens) 217 throws IllegalArgumentException { 218 if (numberOfTokens < 1) { 219 throw new IllegalArgumentException( 220 "The number of tokens must be greater than 0"); 221 } 222 223 return _queue.size() >= numberOfTokens; 224 } 225 226 /** List the tokens stored in the history queue, which are 227 * the N most recent tokens taken from the receiver, beginning with 228 * the oldest, where N is less than or equal to the history capacity. 229 * If the history capacity is INFINITE_CAPACITY, then the enumeration 230 * includes all tokens previously taken from the receiver. If the 231 * history capacity is zero, then return an empty enumeration. 232 * @return An enumeration of tokens. 233 * @deprecated Used historyElementList() instead. 234 */ 235 @Deprecated 236 public List historyElementList() { 237 return _queue.historyElementList(); 238 } 239 240 /** Enumerate the tokens stored in the history queue, which are 241 * the N most recent tokens taken from the receiver, beginning with 242 * the oldest, where N is less than or equal to the history capacity. 243 * If the history capacity is INFINITE_CAPACITY, then the enumeration 244 * includes all tokens previously taken from the receiver. If the 245 * history capacity is zero, then return an empty enumeration. 246 * @return An enumeration of tokens. 247 * @deprecated Used historyElementList() instead. 248 */ 249 @Deprecated 250 public Enumeration historyElements() { 251 return Collections.enumeration(historyElementList()); 252 } 253 254 /** Return the number of tokens in history. 255 * @return The number of tokens in history. 256 */ 257 public int historySize() { 258 return _queue.historySize(); 259 } 260 261 /** Put a token to the receiver. If the receiver is full, throw an 262 * exception. If the argument is null, do nothing. 263 * @param token The token to be put to the receiver. 264 * @exception NoRoomException If the receiver is full. 265 */ 266 @Override 267 public void put(Token token) { 268 if (token == null) { 269 return; 270 } 271 if (!_queue.put(token)) { 272 throw new NoRoomException(getContainer(), 273 "Queue is at capacity. Cannot put a token."); 274 } 275 } 276 277 /** Set receiver capacity. Use INFINITE_CAPACITY to indicate unbounded 278 * capacity (which is the default). If the number of tokens currently 279 * in the receiver exceeds the desired capacity, throw an exception. 280 * @param capacity The desired receiver capacity. 281 * @exception IllegalActionException If the receiver has more tokens 282 * than the proposed capacity or the proposed capacity is illegal. 283 * @see #getCapacity() 284 */ 285 public void setCapacity(int capacity) throws IllegalActionException { 286 try { 287 _queue.setCapacity(capacity); 288 } catch (IllegalActionException ex) { 289 throw new IllegalActionException(getContainer(), ex, 290 "Failed to set capacity to " + capacity); 291 } 292 } 293 294 /** Set the capacity of the history queue. Use 0 to disable the 295 * history mechanism and INFINITE_CAPACITY to make the history 296 * capacity unbounded. If the size of the history queue exceeds 297 * the desired capacity, then remove the oldest tokens from the 298 * history queue until its size equals the proposed capacity. 299 * Note that this can be used to clear the history queue by 300 * supplying 0 as the argument. 301 * @param capacity The desired history capacity. 302 * @exception IllegalActionException If the desired capacity is illegal. 303 * @see #getHistoryCapacity() 304 */ 305 public void setHistoryCapacity(int capacity) throws IllegalActionException { 306 try { 307 _queue.setHistoryCapacity(capacity); 308 } catch (IllegalActionException ex) { 309 throw new IllegalActionException(getContainer(), ex, 310 "Failed to setHistoryCapacity to " + capacity); 311 } 312 } 313 314 /** Return the number of tokens in the receiver. 315 * @return The number of tokens in the receiver. 316 */ 317 public int size() { 318 return _queue.size(); 319 } 320 321 /////////////////////////////////////////////////////////////////// 322 //// public variables //// 323 324 /** Used to indicate that the size of this queue receiver is infinite. 325 */ 326 public static final int INFINITE_CAPACITY = FIFOQueue.INFINITE_CAPACITY; 327 328 /////////////////////////////////////////////////////////////////// 329 //// private variables //// 330 331 /** This is the queue in which data is stored. 332 */ 333 protected FIFOQueue _queue = new FIFOQueue(); 334}