001/* A composite actor that executes a submodel in fire(). 002 003 Copyright (c) 2003-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.lib.hoc; 030 031import java.util.Iterator; 032 033import ptolemy.actor.TypedIOPort; 034import ptolemy.data.IntToken; 035import ptolemy.data.expr.Parameter; 036import ptolemy.data.expr.Variable; 037import ptolemy.data.type.BaseType; 038import ptolemy.kernel.CompositeEntity; 039import ptolemy.kernel.util.Attribute; 040import ptolemy.kernel.util.IllegalActionException; 041import ptolemy.kernel.util.InternalErrorException; 042import ptolemy.kernel.util.NameDuplicationException; 043import ptolemy.kernel.util.Workspace; 044 045/////////////////////////////////////////////////////////////////// 046//// ExecuteCompositeActor 047 048/** 049 This is a composite actor that can execute the contained model 050 completely, as if it were a top-level model, on each firing. 051 This can be used to define an actor whose firing behavior 052 is given by a complete execution of a submodel. 053 <p> 054 An instance of this actor can have ports added to it. If it has 055 input ports, then on each firing, before executing the referenced 056 model, this actor will read an input token from the input port, if 057 there is one, and use it to set the value of a top-level parameter 058 in the contained model that has the same name as the port, if there 059 is one. The simplest way to ensure that there is a matching parameter 060 is to use a PortParameter for inputs. However, this actor will work 061 also for ordinary ports. In this case, if this actor has a 062 parameter with the same name as the port, and it is an instance 063 of Variable (or its derived class Parameter), then the token 064 read at the input is moved into it using its setToken() method. 065 Otherwise, if it is an instance of Settable, then a string representation 066 of the token is copied using the setExpression() method. 067 Input ports should not be multiports, and if they are, then 068 all but the first channel will be ignored. 069 <p> 070 If this actor has output ports and the contained model is executed, 071 then upon completion of that execution, if this actor has parameters 072 whose names match those of the output ports, then the final value of 073 those parameters is sent to the output ports. If such a parameter is an 074 instance of Variable (or its derived class Parameter), then its 075 contained token is sent to the output token. Otherwise, if it is an 076 instance of Settable, then a string token is produced on the output 077 with its value equal to that returned by getExpression() of the 078 Settable. Output ports should not be multiports. If they are, 079 then all but the first channel will be ignored. 080 A typical use of this actor will use the SetVariable actor 081 inside to define the value of the output port. 082 <p> 083 In preinitialize(), type constraints are set up so that input 084 and output ports with (name) matching parameters are constrained 085 to have compatible types. Note that if the ports or parameters 086 are changed during execution, then it will be necessary to set 087 up matching type constraints by hand. Since this isn't possible 088 to do from Vergil, the ports and parameters of this actor 089 should not be changed using Vergil during execution. 090 <p> 091 This actor also overrides the requestChange() method and the 092 executeChangeRequests() method to execute the given change. It does not 093 delegate the change request to the container, but executes the request 094 immediately or records it, depending on whether setDeferringChangeRequests() 095 has been called with a true argument. 096 097 @author Edward A. Lee, Yang Zhao, Elaine Cheong 098 @version $Id$ 099 @since Ptolemy II 10.0 100 @see ModelReference 101 @see ptolemy.actor.lib.SetVariable 102 @Pt.ProposedRating Yellow (eal) 103 @Pt.AcceptedRating Red (eal) 104 */ 105public class ExecuteCompositeActor extends LifeCycleManager { 106 /** Construct an actor in the default workspace with no 107 * container and an empty string as its name. Add the actor to the 108 * workspace directory. You should set the local director or 109 * executive director before attempting to send data to the actor or 110 * to execute it. Increment the version number of the workspace. 111 * @exception NameDuplicationException If there is already a parameter with 112 * name firingCountLimit. 113 * @exception IllegalActionException If the firingCountLimit cannot be 114 * initialized. 115 */ 116 public ExecuteCompositeActor() 117 throws IllegalActionException, NameDuplicationException { 118 super(); 119 _init(); 120 } 121 122 /** Construct a ExecuteCompositeActor in the specified workspace with 123 * no container and an empty string as a name. You can then change 124 * the name with setName(). If the workspace argument is null, then 125 * use the default workspace. You should set the local director or 126 * executive director before attempting to send data to the actor 127 * or to execute it. Add the actor to the workspace directory. 128 * Increment the version number of the workspace. 129 * @param workspace The workspace that will list the actor. 130 * @exception NameDuplicationException If there is already a parameter with 131 * name firingCountLimit. 132 * @exception IllegalActionException If the firingCountLimit cannot be 133 * initialized. 134 */ 135 public ExecuteCompositeActor(Workspace workspace) 136 throws IllegalActionException, NameDuplicationException { 137 super(workspace); 138 _init(); 139 } 140 141 /** Construct a ExecuteCompositeActor with a name and a container. 142 * The container argument must not be null, or a 143 * NullPointerException will be thrown. This actor will use the 144 * workspace of the container for synchronization and version counts. 145 * If the name argument is null, then the name is set to the empty string. 146 * Increment the version of the workspace. This actor will have no 147 * local director initially, and its executive director will be simply 148 * the director of the container. 149 * 150 * @param container The container. 151 * @param name The name of this actor. 152 * @exception IllegalActionException If the container is incompatible 153 * with this actor. 154 * @exception NameDuplicationException If the name coincides with 155 * an actor already in the container. 156 */ 157 public ExecuteCompositeActor(CompositeEntity container, String name) 158 throws IllegalActionException, NameDuplicationException { 159 super(container, name); 160 _init(); 161 } 162 163 /////////////////////////////////////////////////////////////////// 164 //// parameters //// 165 166 /** Indicator to run the contained model a limited number of times. 167 * If this parameter has a value greater than zero, then after 168 * firing the inside model the specified number of times, 169 * {@link #postfire()} will return false. This is an int that 170 * defaults to 0. 171 */ 172 public Parameter firingCountLimit; 173 174 /////////////////////////////////////////////////////////////////// 175 //// public methods //// 176 177 /** Run a complete execution of the contained model. A complete 178 * execution consists of invocation of super.initialize(), 179 * repeated invocations of super.prefire(), super.fire(), and 180 * super.postfire(), followed by super.wrapup(). The invocations 181 * of prefire(), fire(), and postfire() are repeated until either 182 * the model indicates it is not ready to execute (prefire() 183 * returns false), or it requests a stop (postfire() returns 184 * false or stop() is called). Before running the complete 185 * execution, this method calls the director's transferInputs() 186 * method to read any available inputs. After running the 187 * complete execution, it calls transferOutputs(). The subclass 188 * of this can set the <i>_isSubclassOfExecuteCompositeActor</i> to be 189 * true to call the fire method of the superclass of this. 190 * @exception IllegalActionException If there is no director, or if 191 * the director's action methods throw it. 192 */ 193 @Override 194 public void fire() throws IllegalActionException { 195 super.fire(); 196 if (_debugging) { 197 _debug("---- calling fire(), which will execute a subsystem."); 198 } 199 200 _executeInsideModel(); 201 } 202 203 /** Initialize this actor, which in this case, does nothing. The 204 * initialization of the submodel is accomplished in fire(). The 205 * subclass of this can set the 206 * <i>_isSubclassOfExecuteCompositeActor</i> to be true to call the 207 * initialize method of the superclass of this. 208 * @exception IllegalActionException Not thrown in this base class, 209 * but declared so the subclasses can throw it. 210 */ 211 @Override 212 public void initialize() throws IllegalActionException { 213 super.initialize(); 214 if (_debugging) { 215 _debug("Called initialize(), which does nothing."); 216 } 217 _iteration = 0; 218 } 219 220 /** Return true, indicating that execution can continue. The 221 * subclass of this can set the 222 * <i>_isSubclassOfExecuteCompositeActor</i> to be true to call the 223 * postfire method of the superclass of this. 224 * @exception IllegalActionException Not thrown in this base class, 225 * but declared so the subclasses can throw it. 226 */ 227 @Override 228 public boolean postfire() throws IllegalActionException { 229 int limitValue = ((IntToken) firingCountLimit.getToken()).intValue(); 230 if (limitValue > 0) { 231 _iteration++; 232 if (_iteration >= limitValue) { 233 if (_debugging) { 234 _debug("Called postfire(), which returns false."); 235 } 236 return false; 237 } 238 } 239 return super.postfire(); 240 } 241 242 /** Override the base class to set type constraints between the 243 * output ports and parameters of this actor whose name matches 244 * the output port. If there is no such parameter, then create 245 * an instance of Variable with a matching name and set up the 246 * type constraints to that instance. The type of the output 247 * port is constrained to be at least that of the parameter 248 * or variable. 249 * @exception IllegalActionException If there is no director, or if 250 * the director's preinitialize() method throws it, or if this actor 251 * is not opaque. 252 */ 253 @Override 254 public void preinitialize() throws IllegalActionException { 255 super.preinitialize(); 256 257 Iterator ports = outputPortList().iterator(); 258 259 while (ports.hasNext()) { 260 TypedIOPort port = (TypedIOPort) ports.next(); 261 262 // Ensure that the production rate is one. 263 // FIXME: This may not be right if there is no 264 // actual source of data for this port (e.g. no 265 // SetVariable actor). 266 Variable rate = (Variable) port.getAttribute("tokenProductionRate"); 267 268 if (rate == null) { 269 try { 270 rate = new Variable(port, "tokenProductionRate"); 271 } catch (NameDuplicationException e) { 272 throw new InternalErrorException(e); 273 } 274 } 275 276 rate.setToken(new IntToken(1)); 277 278 String portName = port.getName(); 279 Attribute attribute = getAttribute(portName); 280 281 if (attribute == null) { 282 try { 283 workspace().getWriteAccess(); 284 attribute = new Variable(this, portName); 285 } catch (NameDuplicationException ex) { 286 throw new InternalErrorException(ex); 287 } finally { 288 workspace().doneWriting(); 289 } 290 } 291 292 // attribute is now assured to be non-null. 293 if (attribute instanceof Variable) { 294 port.setTypeAtLeast((Variable) attribute); 295 } else { 296 // Assume the port type must be a string. 297 port.setTypeEquals(BaseType.STRING); 298 } 299 } 300 } 301 302 /** Override the base class to do nothing. 303 * @exception IllegalActionException Not thrown in this base class, 304 * but declared so the subclasses can throw it. 305 */ 306 @Override 307 public void wrapup() throws IllegalActionException { 308 // No need to call super.wrapup(), the parent class 309 // _executeInsideModel() will do it for us. 310 if (_debugging) { 311 _debug("Called wrapup(), which does nothing."); 312 } 313 } 314 315 /////////////////////////////////////////////////////////////////// 316 //// private methods //// 317 318 /** Set the class name and create the parameters. 319 * @exception NameDuplicationException If there is already a parameter with 320 * name firingCountLimit. 321 * @exception IllegalActionException If the firingCountLimit cannot be 322 * initialized. 323 */ 324 private void _init() 325 throws IllegalActionException, NameDuplicationException { 326 // By default, when exporting MoML, the class name is whatever 327 // the Java class is, which in this case is ExecuteCompositeActor. 328 // In derived classes, however, we usually do not want to identify 329 // the class name as that of the derived class, but rather want 330 // to identify it as ExecuteCompositeActor. This way, the MoML 331 // that is exported does not depend on the presence of the 332 // derived class Java definition. Thus, we force the class name 333 // here to be ExecuteCompositeActor. 334 setClassName("ptolemy.actor.lib.hoc.ExecuteCompositeActor"); 335 336 firingCountLimit = new Parameter(this, "firingCountLimit"); 337 firingCountLimit.setTypeEquals(BaseType.INT); 338 firingCountLimit.setExpression("0"); 339 } 340 341 /////////////////////////////////////////////////////////////////// 342 //// private variables //// 343 344 /** The count of iterations. */ 345 private int _iteration; 346}