001/* A CaseDirector governs the execution of a case actor. 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 */ 027package ptolemy.actor.lib.hoc; 028 029import java.util.Iterator; 030 031import ptolemy.actor.Actor; 032import ptolemy.actor.Director; 033import ptolemy.actor.FiringEvent; 034import ptolemy.actor.IOPort; 035import ptolemy.actor.IOPortEvent; 036import ptolemy.actor.Mailbox; 037import ptolemy.actor.NoRoomException; 038import ptolemy.actor.NoTokenException; 039import ptolemy.actor.Receiver; 040import ptolemy.actor.parameters.ParameterPort; 041import ptolemy.actor.parameters.PortParameter; 042import ptolemy.actor.util.Time; 043import ptolemy.data.StringToken; 044import ptolemy.data.Token; 045import ptolemy.kernel.ComponentEntity; 046import ptolemy.kernel.CompositeEntity; 047import ptolemy.kernel.util.IllegalActionException; 048import ptolemy.kernel.util.InternalErrorException; 049import ptolemy.kernel.util.NameDuplicationException; 050import ptolemy.kernel.util.Nameable; 051 052/////////////////////////////////////////////////////////////////// 053//// CaseDirector 054 055/** 056 An CaseDirector governs the execution of a Case actor. 057 This director simply delegates to the refinement whose name 058 matches the value of the current control input. 059 060 @author Edward A. Lee 061 @version $Id$ 062 @since Ptolemy II 5.2 063 @Pt.ProposedRating Yellow (eal) 064 @Pt.AcceptedRating Red (hyzheng) 065 */ 066public class CaseDirector extends Director { 067 068 /** Construct a director in the given container with the given name. 069 * The container argument must not be null, or a 070 * NullPointerException will be thrown. 071 * If the name argument is null, then the name is set to the 072 * empty string. Increment the version number of the workspace. 073 * @param container Container of this director. 074 * @param name Name of this director. 075 * @exception IllegalActionException If the name has a period in it, or 076 * the director is not compatible with the specified container. 077 * @exception NameDuplicationException If the container not a 078 * CompositeActor and the name collides with an entity in the container. 079 */ 080 public CaseDirector(CompositeEntity container, String name) 081 throws IllegalActionException, NameDuplicationException { 082 super(container, name); 083 } 084 085 /////////////////////////////////////////////////////////////////// 086 //// public methods //// 087 088 /** Schedule a firing of the given actor at the given time. 089 * If there is an executive director, this method delegates to it. 090 * Otherwise, it sets its own notion of current time to that 091 * specified in the argument. The reason for this is to enable 092 * Case to be a top-level actor and to support the design pattern 093 * where a director requests a refiring at the next time it wishes 094 * to be awakened, just prior to returning from fire(). DEDirector, 095 * for example, does that, as does the SDFDirector if the period 096 * parameter is set. 097 * @param actor The actor scheduled to be fired. 098 * @param time The scheduled time. 099 * @param microstep The microstep. 100 * @return The time returned by the executive director, or 101 * or the specified time if there isn't one. 102 * @exception IllegalActionException If by the executive director. 103 */ 104 @Override 105 public Time fireAt(Actor actor, Time time, int microstep) 106 throws IllegalActionException { 107 // Note that the actor parameter is ignored, because it does not 108 // matter which actor requests firing. 109 Nameable container = getContainer(); 110 111 if (container instanceof Actor) { 112 Actor modalModel = (Actor) container; 113 Director executiveDirector = modalModel.getExecutiveDirector(); 114 115 if (executiveDirector != null) { 116 return executiveDirector.fireAt(modalModel, time, microstep); 117 } 118 } 119 setModelTime(time); 120 return time; 121 } 122 123 /** Fire the current refinement. 124 * @exception IllegalActionException If refinement throws it. 125 */ 126 @Override 127 public void fire() throws IllegalActionException { 128 if (_debugging) { 129 _debug("Calling fire()"); 130 } 131 Case container = (Case) getContainer(); 132 if (container._current == null) { 133 throw new IllegalActionException(container, 134 "Has no current refinement"); 135 } 136 if (_debugging) { 137 _debug(new FiringEvent(this, container._current, 138 FiringEvent.BEFORE_FIRE)); 139 } 140 container._current.fire(); 141 if (_debugging) { 142 _debug("Called fire()"); 143 _debug(new FiringEvent(this, container._current, 144 FiringEvent.AFTER_FIRE)); 145 } 146 } 147 148 /** Return a receiver that is a one-place buffer. A token put into the 149 * receiver will overwrite any token already in the receiver. 150 * @return A receiver that is a one-place buffer. 151 */ 152 @Override 153 public Receiver newReceiver() { 154 return new Mailbox() { 155 @Override 156 public boolean hasRoom() { 157 return true; 158 } 159 160 @Override 161 public void put(Token token) { 162 try { 163 if (hasToken() == true) { 164 get(); 165 } 166 super.put(token); 167 } catch (NoRoomException ex) { 168 throw new InternalErrorException( 169 "One-place buffer: " + ex.getMessage()); 170 } catch (NoTokenException ex) { 171 throw new InternalErrorException( 172 "One-place buffer: " + ex.getMessage()); 173 } 174 } 175 }; 176 } 177 178 /** Read the control token input, transfer input tokens, 179 * and invoke prefire() of the selected refinement. 180 * 181 * @exception IllegalActionException If there is no director, 182 * or if the director's prefire() method throws it, or if this actor 183 * is not opaque. 184 */ 185 @Override 186 public boolean prefire() throws IllegalActionException { 187 if (_debugging) { 188 _debug("Calling prefire()"); 189 } 190 191 try { 192 _workspace.getReadAccess(); 193 super.prefire(); 194 195 Case container = (Case) getContainer(); 196 // Read from port parameters, including the control port. 197 Iterator portParameters = container 198 .attributeList(PortParameter.class).iterator(); 199 while (portParameters.hasNext()) { 200 PortParameter portParameter = (PortParameter) portParameters 201 .next(); 202 portParameter.update(); 203 } 204 205 String controlValue; 206 Token controlToken = container.control.getToken(); 207 // If it's a string, use stringValue() otherwise there 208 // are quotes around the string. 209 if (controlToken instanceof StringToken) { 210 controlValue = ((StringToken) controlToken).stringValue(); 211 } else { 212 controlValue = controlToken.toString(); 213 } 214 215 ComponentEntity refinement = container.getEntity(controlValue); 216 if (!(refinement instanceof Refinement)) { 217 refinement = container._default; 218 } 219 container._current = (Refinement) refinement; 220 221 // Transfer input tokens. 222 for (Iterator inputPorts = container.inputPortList() 223 .iterator(); inputPorts.hasNext() && !_stopRequested;) { 224 IOPort port = (IOPort) inputPorts.next(); 225 226 if (!(port instanceof ParameterPort)) { 227 Receiver[][] insideReceivers = port.deepGetReceivers(); 228 for (int i = 0; i < port.getWidth(); i++) { 229 if (port.hasToken(i)) { 230 Token token = port.get(i); 231 if (insideReceivers != null 232 && insideReceivers[i] != null) { 233 for (int j = 0; j < insideReceivers[i].length; j++) { 234 if (insideReceivers[i][j].getContainer() 235 .getContainer() == refinement) { 236 237 if (_debugging) { 238 _debug(new IOPortEvent(port, 239 insideReceivers[i][j] 240 .getContainer(), 241 true, i, false, token)); 242 } 243 244 insideReceivers[i][j].put(token); 245 246 if (_debugging) { 247 _debug(new IOPortEvent(port, 248 insideReceivers[i][j] 249 .getContainer(), 250 false, i, false, token)); 251 _debug(getFullName(), 252 "transferring input from " 253 + port.getFullName() 254 + " to " 255 + insideReceivers[i][j] 256 .getContainer() 257 .getFullName()); 258 } 259 } 260 } 261 } 262 } 263 } 264 } 265 } 266 if (_stopRequested) { 267 return false; 268 } 269 if (_debugging) { 270 _debug(new FiringEvent(this, container._current, 271 FiringEvent.BEFORE_PREFIRE)); 272 } 273 boolean result = container._current.prefire(); 274 if (_debugging) { 275 _debug(new FiringEvent(this, container._current, 276 FiringEvent.AFTER_PREFIRE)); 277 } 278 return result; 279 } finally { 280 _workspace.doneReading(); 281 } 282 } 283 284 /** Invoke the postfire() method of the current local director. 285 * @return True if the execution can continue into the next iteration. 286 * @exception IllegalActionException If there is no director, 287 * or if the director's postfire() method throws it, or if this 288 * actor is not opaque. 289 */ 290 @Override 291 public boolean postfire() throws IllegalActionException { 292 if (_debugging) { 293 _debug("Calling postfire()"); 294 } 295 Case container = (Case) getContainer(); 296 297 if (_debugging) { 298 _debug(new FiringEvent(this, container._current, 299 FiringEvent.BEFORE_POSTFIRE)); 300 } 301 302 boolean result = container._current.postfire(); 303 304 if (_debugging) { 305 _debug(new FiringEvent(this, container._current, 306 FiringEvent.AFTER_POSTFIRE)); 307 } 308 309 return result && !_finishRequested; 310 } 311}