001/* The receiver for use with FixedPointDirector or any of its subclasses. 002 003 Copyright (c) 2006-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 */ 028package ptolemy.actor.sched; 029 030import java.util.LinkedList; 031import java.util.List; 032 033import ptolemy.actor.AbstractReceiver; 034import ptolemy.actor.IOPort; 035import ptolemy.actor.NoTokenException; 036import ptolemy.data.Token; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.InvalidStateException; 039 040/////////////////////////////////////////////////////////////////// 041//// FixedPointReceiver 042 043/** 044 The receiver for use with FixedPointDirector or any of its subclasses. 045 This receiver has capacity 1. 046 The status of this receiver can be either <i>known</i> or <i>unknown</i>. 047 If it is known, then it can be either <i>present</i> or <i>absent</i>. 048 If it is present, then it has a token, which provides a value. 049 <p> 050 At first, an instance of this class has status unknown. 051 The clear() method makes the status known and absent. 052 The put() method makes the status known and present, and provides a value. 053 The reset() method reverts the status to unknown. 054 Once the status of a receiver becomes known, the value 055 cannot be changed, nor can the status be changed from present to absent 056 or vice versa. To change the value or the status, call reset() first. 057 Normally, the reset() method is called only by the director and constructors. 058 <p> 059 The isKnown() method returns true if the receiver has status known. 060 The hasRoom() method returns true if the receiver has status unknown. 061 If the receiver has a known status, the hasToken() method returns true 062 if the receiver contains a token. If the receiver has an unknown status, 063 the hasToken() method will throw an InvalidStateException. 064 <p> 065 This class is based on the original SRReceiver, written by Paul Whitaker. 066 067 @author Haiyang Zheng and Edward A. Lee 068 @version $Id$ 069 @since Ptolemy II 5.2 070 @Pt.ProposedRating Green (hyzheng) 071 @Pt.AcceptedRating Yellow (eal) 072 */ 073public class FixedPointReceiver extends AbstractReceiver { 074 075 /** Construct an FixedPointReceiver with unknown status. 076 * This constructor does not need a director. 077 */ 078 public FixedPointReceiver() { 079 this(null); 080 } 081 082 /** Construct an FixedPointReceiver with unknown status. 083 * @param director The director of this receiver. 084 */ 085 public FixedPointReceiver(FixedPointDirector director) { 086 super(); 087 reset(); 088 _director = director; 089 } 090 091 /////////////////////////////////////////////////////////////////// 092 //// public methods //// 093 094 /** Set the status of this receiver to be known and absent. 095 * @exception IllegalActionException If this receiver is known and 096 * present. 097 */ 098 @Override 099 public void clear() throws IllegalActionException { 100 if (isKnown()) { 101 if (hasToken()) { 102 throw new IllegalActionException(getContainer(), 103 "Cannot change the status from present" 104 + " to absent."); 105 } 106 } else { 107 _token = null; 108 _known = true; 109 if (_director != null) { 110 _director._receiverChanged(); 111 } 112 } 113 } 114 115 /** Return a list with the token currently in the receiver, or 116 * an empty list if there is no such token. 117 * @return A list of instances of Token. 118 */ 119 @Override 120 public List<Token> elementList() { 121 List<Token> result = new LinkedList<Token>(); 122 if (_token != null) { 123 result.add(_token); 124 } 125 return result; 126 } 127 128 /** Return the contained token. If there is no token or the status 129 * of this receiver is unknown, throw an exception. 130 * @return The token contained in the receiver. 131 * @exception NoTokenException If there is no token. 132 * @exception InvalidStateException If the status is unknown. 133 */ 134 @Override 135 public Token get() throws NoTokenException { 136 if (!isKnown()) { 137 throw new InvalidStateException( 138 "FixedPointReceiver: get() called on an " 139 + "FixedPointReceiver " + "with status unknown."); 140 } 141 if (_token == null) { 142 throw new NoTokenException(_director, 143 "FixedPointReceiver: Attempt to get data from an " 144 + "empty receiver."); 145 } 146 return _token; 147 } 148 149 /** Return true if the status of the receiver is unknown. 150 * @return True if the status of the receiver is unknown. 151 * @see #isKnown() 152 */ 153 @Override 154 public boolean hasRoom() { 155 return !isKnown(); 156 } 157 158 /** If the argument is 1, return true if the status of the receiver 159 * is unknown. Otherwise, throw an exception. This receiver has 160 * capacity one. 161 * @param numberOfTokens The number of tokens to put into the receiver. 162 * @return True if the receiver can accept a token. 163 * @exception IllegalArgumentException If the argument is not positive. 164 * @see #isKnown() 165 * @see #hasRoom() 166 */ 167 @Override 168 public boolean hasRoom(int numberOfTokens) throws IllegalArgumentException { 169 if (numberOfTokens < 1) { 170 throw new IllegalArgumentException( 171 "FixedPointReceiver: hasRoom() requires a " 172 + "positive argument."); 173 } 174 if (numberOfTokens == 1) { 175 return !isKnown(); 176 } 177 return false; 178 } 179 180 /** Return true if the receiver contains a token, and false otherwise. 181 * If the receiver has status unknown, this method will throw an 182 * exception. 183 * @return True if this receiver contains a token. 184 * @exception InvalidStateException If the status is unknown. 185 */ 186 @Override 187 public boolean hasToken() { 188 if (isKnown()) { 189 return _token != null; 190 } else { 191 throw new InvalidStateException(getContainer(), 192 "hasToken() called on FixedPointReceiver with " 193 + "unknown status."); 194 } 195 } 196 197 /** If the argument is 1, return true if the receiver 198 * contains a token, and false otherwise. If the argument is 199 * larger than 1, return false (this receiver has capacity one). 200 * If the receiver has status unknown, throw an exception. 201 * @param numberOfTokens The number of tokens. 202 * @return True if the argument is 1 and the receiver has a token. 203 * @exception IllegalArgumentException If the argument is not positive. 204 * @see #hasToken() 205 * @exception InvalidStateException If the status is unknown. 206 */ 207 @Override 208 public boolean hasToken(int numberOfTokens) { 209 if (!isKnown()) { 210 throw new InvalidStateException(getContainer(), "hasToken(int)" 211 + " called on FixedPointReceiver with unknown status."); 212 } 213 if (numberOfTokens < 1) { 214 throw new IllegalArgumentException( 215 "FixedPointReceiver: hasToken(int) requires a " 216 + "positive argument."); 217 } 218 if (numberOfTokens == 1) { 219 return hasToken(); 220 } 221 return false; 222 } 223 224 /** Return true if this receiver has status known, that is, this 225 * receiver either is either known to have a token or known to 226 * not to have a token. 227 * @return True if this receiver has status known. 228 */ 229 @Override 230 public boolean isKnown() { 231 IOPort container = getContainer(); 232 if (container != null && container.sourcePortList().size() == 0 233 && container.insideSourcePortList().size() == 0) { 234 // There are no sources connected to the container port, 235 // so the port is presumably empty and known. 236 return true; 237 } 238 return _known; 239 } 240 241 /** If the specified token is non-null, then 242 * set the status of this receiver to known and present, and to contain the 243 * specified token. If the receiver is already known and the value of 244 * the contained token is different from that of the new token, throw 245 * an exception. If the specified token is null, then set the status to 246 * be known and absent (by calling {@link #clear()}). 247 * @param token The token to be put into this receiver. 248 * @exception IllegalArgumentException If the argument is null. 249 * @exception IllegalActionException If the status is known and absent, 250 * or a token is present but not have the same value, or a token 251 * is present and cannot be compared to the specified token. 252 */ 253 @Override 254 public void put(Token token) throws IllegalActionException { 255 if (token == null) { 256 clear(); 257 return; 258 } 259 if (!isKnown()) { 260 _token = token; 261 _known = true; 262 if (_director != null) { 263 _director._receiverChanged(); 264 } 265 } else { 266 if (!hasToken()) { 267 throw new IllegalActionException(getContainer(), 268 "Cannot change from an absent status " 269 + "to a present status. Call reset() first."); 270 } else { 271 if (!token.isEqualTo(_token).booleanValue()) { 272 throw new IllegalActionException(getContainer(), 273 "Cannot put a token with a different value " + token 274 + " into a receiver with an already established value " 275 + _token); 276 } 277 } 278 } 279 } 280 281 /** Reset the receiver by deleting any contained tokens and setting 282 * the status of this receiver to unknown, unless the containing port 283 * has no sources, in which case set to known and absent. This is called 284 * by the , normally in its initialize() and postfire() 285 * methods. 286 */ 287 @Override 288 public void reset() { 289 _token = null; 290 _known = false; 291 } 292 293 /** Set the container. This overrides the base class so that 294 * if the container is being set to null, and if the director of 295 * this receiver is not null, this method removes the receiver 296 * from the list in that director. 297 * @param port The container. 298 * @exception IllegalActionException If the container is not of 299 * an appropriate subclass of IOPort. Not thrown in this base class, 300 * but may be thrown in derived classes. 301 * @see #getContainer() 302 */ 303 @Override 304 public void setContainer(IOPort port) throws IllegalActionException { 305 if (port == null && _director != null) { 306 _director._receivers.remove(this); 307 } 308 super.setContainer(port); 309 } 310 311 /////////////////////////////////////////////////////////////////// 312 //// protected fields //// 313 314 /** The director of this receiver. */ 315 protected FixedPointDirector _director; 316 317 /** A flag indicating whether this receiver has status known. */ 318 protected boolean _known = false; 319 320 /** The token held. */ 321 protected Token _token = null; 322}