001/* Discrete Event (DE) domain receiver. 002 003 Copyright (c) 1998-2015 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.domains.de.kernel; 029 030import java.util.LinkedList; 031import java.util.List; 032 033import ptolemy.actor.AbstractReceiver; 034import ptolemy.actor.Actor; 035import ptolemy.actor.CompositeActor; 036import ptolemy.actor.Director; 037import ptolemy.actor.IOPort; 038import ptolemy.actor.NoRoomException; 039import ptolemy.actor.NoTokenException; 040import ptolemy.data.Token; 041import ptolemy.kernel.util.IllegalActionException; 042 043/////////////////////////////////////////////////////////////////// 044//// DEReceiver 045 046/** An implementation of the ptolemy.actor.Receiver interface for the 047 DE domain. 048 <p> 049 The put() method stores the given token in this receiver and posts a 050 trigger event to the director. The director is responsible to dequeue that 051 trigger event and invoke the actor that contains this receiver. 052 The get() method returns the first available token from the receiver. 053 <p> 054 Before firing an actor, the director is expected to put at least one 055 token into at least one of the receivers contained by the actor. 056 057 @author Lukito Muliadi, Edward A. Lee, Jie Liu, Haiyang Zheng 058 @version $Id$ 059 @since Ptolemy II 0.2 060 @Pt.ProposedRating Green (hyzheng) 061 @Pt.AcceptedRating Yellow (hyzheng) 062 */ 063public class DEReceiver extends AbstractReceiver { 064 /** Construct an empty DEReceiver with no container. 065 */ 066 public DEReceiver() { 067 super(); 068 } 069 070 /** Construct an empty DEReceiver with the specified container. 071 * @param container The container. 072 * @exception IllegalActionException If the container does 073 * not accept this receiver. 074 */ 075 public DEReceiver(IOPort container) throws IllegalActionException { 076 super(container); 077 } 078 079 /////////////////////////////////////////////////////////////////// 080 //// public methods //// 081 082 /** Clear this receiver of any contained tokens. 083 */ 084 @Override 085 public void clear() { 086 _tokens.clear(); 087 } 088 089 /** Return a list with tokens that are currently in the receiver 090 * available for get() or getArray(), beginning with the oldest one. 091 * @return A list of instances of Token. 092 */ 093 @Override 094 public List<Token> elementList() { 095 return _tokens; 096 } 097 098 /** Get the first token from the receiver. The token returned is one that 099 * was put in the receiver with a timestamp equal to or earlier than 100 * the current time. If there is no token, throw an exception. If this 101 * receiver contains more than one event, the oldest event is removed 102 * first. In other words, this receiver has a FIFO behavior. 103 * @return A token. 104 * @exception NoTokenException If there are no more tokens. This is 105 * a runtime exception, so it need not to be declared explicitly. 106 */ 107 @Override 108 public Token get() throws NoTokenException { 109 if (_tokens.isEmpty()) { 110 throw new NoTokenException(getContainer(), 111 "No more tokens in the DE receiver."); 112 } 113 114 return (Token) _tokens.removeFirst(); 115 } 116 117 /** Return true, indicating that there is always room. 118 * @return True. 119 */ 120 @Override 121 public final boolean hasRoom() { 122 return true; 123 } 124 125 /** Return true if the receiver has room for putting the given number of 126 * tokens into it (via the put() method). 127 * Returning true in this method should also guarantee that calling 128 * the put() method will not result in an exception. 129 * @param tokens An int indicating the number of spaces available. 130 * @return True. 131 */ 132 @Override 133 public boolean hasRoom(int tokens) { 134 return true; 135 } 136 137 /** Return true if there is at least one token available to the 138 * get() method. 139 * @return True if there are more tokens. 140 */ 141 @Override 142 public boolean hasToken() { 143 return !_tokens.isEmpty(); 144 } 145 146 /** Return true if there are <i>numberOfTokens</i> 147 * tokens tokens available to the get() method. 148 * @param numberOfTokens An int indicating how many tokens are needed. 149 * @return True if there are numberOfTokens tokens available. 150 */ 151 @Override 152 public boolean hasToken(int numberOfTokens) { 153 return _tokens.size() >= numberOfTokens; 154 } 155 156 /** Put a token into this receiver and post a trigger event to the director. 157 * The director will be responsible to dequeue the trigger event at 158 * the correct timestamp and microstep and invoke the corresponding actor 159 * whose input port contains this receiver. This receiver may contain 160 * more than one events. 161 * @param token The token to be put, or null to put no token. 162 * @exception IllegalActionException If cannot get the director or if 163 * the current microstep is zero. 164 * @exception NoRoomException Not thrown in this class. 165 */ 166 @Override 167 public void put(Token token) 168 throws IllegalActionException, NoRoomException { 169 if (token == null) { 170 return; 171 } 172 DEDirector dir = _getDirector(); 173 dir._enqueueTriggerEvent(getContainer()); 174 _tokens.add(token); 175 } 176 177 /////////////////////////////////////////////////////////////////// 178 //// protected variables //// 179 180 /** The version of the workspace of container, used for 181 * caching by _getDirector(). 182 * Derived classes that modify the cache may need to update 183 * this variable. 184 */ 185 protected long _directorVersion = -1; 186 187 /** List for storing tokens. Access with clear(), add(), and take(). */ 188 protected LinkedList _tokens = new LinkedList(); 189 190 /////////////////////////////////////////////////////////////////// 191 //// private methods //// 192 193 /** Return the director that created this receiver. 194 * If this receiver is an inside receiver of 195 * an output port of an opaque composite actor, 196 * then the director will be the local director 197 * of the container of its port. Otherwise, it's the executive 198 * director of the container of its port.Note that 199 * the director returned is guaranteed to be non-null. 200 * This method is read synchronized on the workspace. 201 * @return An instance of DEDirector. 202 * @exception IllegalActionException If there is no container port, or 203 * if the port has no container actor, or if the actor has no director, 204 * or if the director is not an instance of DEDirector. 205 */ 206 private DEDirector _getDirector() throws IllegalActionException { 207 IOPort port = getContainer(); 208 209 if (port != null) { 210 if (_directorVersion == port.workspace().getVersion()) { 211 return _director; 212 } 213 214 // Cache is invalid. Reconstruct it. 215 try { 216 port.workspace().getReadAccess(); 217 218 Actor actor = (Actor) port.getContainer(); 219 220 if (actor != null) { 221 Director dir; 222 223 if (!port.isInput() && actor instanceof CompositeActor 224 && ((CompositeActor) actor).isOpaque()) { 225 dir = actor.getDirector(); 226 } else { 227 dir = actor.getExecutiveDirector(); 228 } 229 230 if (dir != null) { 231 if (dir instanceof DEDirector) { 232 _director = (DEDirector) dir; 233 _directorVersion = port.workspace().getVersion(); 234 return _director; 235 } else { 236 throw new IllegalActionException(getContainer(), 237 "Does not have a DEDirector."); 238 } 239 } else { 240 throw new IllegalActionException(getContainer(), 241 "No outside director found."); 242 } 243 } 244 } finally { 245 port.workspace().doneReading(); 246 } 247 } 248 249 throw new IllegalActionException(getContainer(), 250 "Does not have an IOPort as the container of the receiver."); 251 } 252 253 /////////////////////////////////////////////////////////////////// 254 //// private variables //// 255 // The director where this DEReceiver should register for De events. 256 private DEDirector _director; 257}